Setup

library(seqinr)
library(ape)  
library(pegas)
library(hierfstat)
library(mmod)
library(adegenet)
library(plyr)
library(strataG)
library(iNEXT)
library(gdm)
library(gdistance)
library(ecodist)
library(dplyr)
library(reshape2)
library(WriteXLS)
library(ggplot2)
library(knitr)
library(vegan)
source("config.R")
source("DIPnet_Stats_Functions.R")
rescale<-function(x){
  normalized<-(x-min(x))/(max(x)-min(x))
  return(normalized)
}
######################################################################
# 1. Import the IPDB and Fst tables
ipdb<-read.table(ipdb_path,sep="\t",header=T,stringsAsFactors = F,quote="", na.strings=c("NA"," ","")) 
#read in geographical regionalizations from Treml
spatial<-read.table(spatial_path, header=T, sep="\t",stringsAsFactors = F, na.strings=c("NA"," ",""), quote="")
#read in geographical regionalizations from Beger
spatial2<-read.table(spatial2_path, header=T,sep="\t", stringsAsFactors = F, na.strings=c("NA"," ",""), quote="")
#read in ABGD groups
abgd<-read.table(abgd_path, header=T, sep="\t", stringsAsFactors = F)
#join spatial
ipdb<-join(ipdb,spatial, by = "IPDB_ID",type = "left")
ipdb<-join(ipdb,spatial2[,c(2,18:24)], by = "IPDB_ID", type = "left")
#join ABGD
ipdb<-join(ipdb,abgd[,c(1,3)], by = "IPDB_ID",type = "left")
# drop hybrids and divergent individuals
ipdb<-ipdb[ipdb$IPDB_ID %in% drops == FALSE, ] 
## remove anything not included in the ecoregions scheme (some dolphins, some COTS from Kingman and Madagascar(?), some A. nigros from Kiribati, som C. auriga from Fakareva, hammerheads from Western Australia, and West Africa, and some dolphins from the middle of the eastern tropical pacific
ipdb_ecoregions<-ipdb[-which(is.na(ipdb$ECOREGION)),]
## remove anything that doesn't occur in the 3 Indo-Pacific realms
ipdb_ip<-ipdb_ecoregions[which(ipdb_ecoregions$REALM %in% c("Central Indo-Pacific","Western Indo-Pacific","Eastern Indo-Pacific")),]
amova_ts_path<-"/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_Species/Hierarchical_structure"
amova_abgd_path<-"/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_ESU/Hierarchical_structure"
# Read in Veron barriers
barriers<-read.csv("VeronBarriers.csv",header=F,stringsAsFactors = F)

Introduction

This is an R Markdown Notebook. I am trying it out as a way to reproducibly document my work on the DIPnet Population Structure Paper.

The overall workflow for this analysis is as follows:

Run AMOVA loops

Given the special considerations, we need to run 4 different flavors of AMOVA: 1. WCTheta and TradSpec 2. WCTheta and ABGD 3. PhiST and TradSpec 4. PhiST and ABGD

Thus, we need to loop through all of the regionalizations above, running all 4 flavors of AMOVA.

## Loop through hypotheses, calculating AMOVA
hypotheses<-c("ECOREGION", "PROVINCE","REALM","Bowen","Keith","Kulbicki_r","Kulbicki_b", "VeronDivis")
amova_list<-list()

for(h in hypotheses){
  hierstats<-hierarchical.structure.mtDNA.db(ipdb = ipdb_ip,level1 = "sample",level2=h,model="raw",ABGD=F,nperm=1)
  amova_list[[h]]<-hierstats
}
  
#load(file.path(amova_ts_path,"PHIST_TradSpecies_raw_amova_output.Rdata"))
## Summarize AMOVA results
amovastats<-summarize_AMOVA(amova_list,hypotheses,specieslist=unique(ipdb$Genus_species_locus))

WriteXLS(amovastats,ExcelFileName=file.path(amova_ts_path,"PHIST_ts_raw_table_amova_output.Rdata.xlsx"),row.names = T)
save(amova_list,file=file.path(amova_abgd_path,"FST_abgd_raw_amova_output.Rdata"))
save(amovastats,file=file.path(amova_abgd_path,"FST_abgd_table_amova_output.Rdata"))

This takes a long time, so we are not running this code in the document, but loading in the results as we go through each consideration

Visualize AMOVA results

FST and Traditional Species Boundaries

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

minBIC<-sapply(crit_df,function(x){x[which.min(x)]}) 
#J&O box 4 eqn 1. scale() seems to be the way to go here, using the minBIC as the centering vector
crit_df_deltaI<-scale(crit_df, center=minBIC, scale=F) 
#J&O box 4 eqn 4. numerator, plus make it a data frame
crit_df_deltaI_b<-as.data.frame(exp(-0.5*crit_df_deltaI)) 
#J&O box 4 eqn 4. denominator
crit_df_deltaI_sums<-sapply(crit_df_deltaI_b,sum,na.rm=T) 
# this time use the scale argument of scale to divide each column by the corresponding sum
crit_df_relative_prob<-scale(crit_df_deltaI_b,center=F,scale=crit_df_deltaI_sums) 
## Make a heatmap of relative probability of each hypothesis
#melt for ggplot2
relprob<-melt(crit_df_relative_prob)
colnames(relprob)<-c("Hypothesis","Species","Relative_Probability")
#baseplot
rp<-ggplot(relprob,aes(y=Species,x=Hypothesis,fill=Relative_Probability))
#add geom_tile, turn the x-axis elements by 90 degrees, reverse the names on the y-axis, and use a diverging color scheme to highlight hypotheses with >50% rel prob.
rp<-rp+geom_tile()+
  theme(axis.text.x = element_text(angle = 90, hjust = 1))+
  ylim(rev(levels(relprob$Species)))+
  scale_fill_gradient2(low = "blue", mid = "white",
                       high = "red", midpoint = 0.5, space = "rgb",
                       na.value = "grey50", guide = "colourbar")
Non Lab interpolation is deprecated
rp

PHIST and Traditional Species Boundaries

Code is suppressed for the other 3 examples

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

Non Lab interpolation is deprecated

FST and ABGD Boundaries

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

Non Lab interpolation is deprecated

PHIST and ABGD Boundaries

Measure Support

Calculate relative probability from Johnson and Omland 2004 and visualize with a heatmap

Non Lab interpolation is deprecated

Calculate Pairwise Differentiation Stats

By sample

diffstats<-pairwise.structure.mtDNA.db(ipdb=ipdb, gdist = "WC Theta", minseqs = 5, minsamps = 3, mintotalseqs = 0, nrep = 0, num.cores = 2, ABGD = T, regionalization = "sample")


save(diffstats, file="/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_ESU/Pairwise_statistics/DIPnet_structure_sample_WCTheta_ABGD.Rdata")

diffstats<-pairwise.structure.mtDNA.db(ipdb=ipdb, gdist = "Jost D", minseqs = 5, minsamps = 3, mintotalseqs = 0, nrep = 0, num.cores = 2, ABGD = T, regionalization = "sample")


save(diffstats, file="/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_ESU/Pairwise_statistics/DIPnet_structure_sample_JostD_ABGD.Rdata")

Generalized Dissimilarity Modeling

Traditional Species Boundaries

  load("/Users/eric/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_Species/Pairwise_statistics/sample/DIPnet_structure_sample_PhiST.Rdata")
esu_loci <- unique(ipdb$Genus_species_locus)
gdm.full<-list()
solution<-list()
nosolution<-list()
nosolution.full<-list()
nosolution.list<-list()
stats.full<-data.frame(Species_Locus=character(0),WithRegionsDeviance=numeric(0),WithRegionsExplainedDeviance=numeric(0),NoRegionsDeviance=numeric(0),NoRegionsExplainedDeviance=numeric(0),DeltaDeviance=numeric(0),Pvalue_regions=numeric(0),Pvalue_dist=numeric(0),stringsAsFactors = F)
stats<-data.frame(Species_Locus=character(0),Barrier=character(0),WithBarrierDeviance=numeric(0),WithBarrierExplainedDeviance=numeric(0),ImportanceDistanceWithBarrier=numeric(0),ImportanceBarrierWithBarrier=numeric(0),NoBarrierDeviance=numeric(0),NoBarrierExplainedDeviance=numeric(0),ImportanceDistanceWithoutBarrier=numeric(0),DeltaDeviance=numeric(0),Pvalue_barrier=numeric(0),Pvalue_dist=numeric(0),MRDM.rsquared=numeric(0),MRDM.rsquared.pvalue=numeric(0),MRDM.dist.pvalue=numeric(0), MRDM.barrier.pvalue=numeric(0),stringsAsFactors = F)
nostats<-NULL
barriertests<-data.frame(Species=character(0),Region1=character(0),NumPops1=numeric(0),Region2=character(0),Numpops2=numeric(0), Test=logical(0), Solution=logical(0),stringsAsFactors = F)
k<-0
for(gsl in esu_loci){ #gsl<-"Linckia_laevigata_CO1" "Tridacna_crocea_CO1" "Lutjanus_kasmira_CYB" "Acanthaster_planci_CO1"
  
  cat("\n","\n","\n","Now starting", gsl, "\n")
  
  if(any(is.na(diffstats[[gsl]]))){cat("NAs in FST table, No gdm calculated"); next}
  
  if(diffstats[[gsl]]=="Fewer than 3 sampled populations after filtering. No stats calculated"){nostats<-c(nostats,gsl);next}
  
  #pull out the data for this genus-species-locus (gsl)
  sp<-ipdb[which(ipdb$Genus_species_locus==gsl),]
  #clean weird backslashes from names
  sp$locality<-gsub("\"","",sp$locality)
  
  sp$sample<-paste(sp$locality,round(sp$decimalLatitude, digits=0),round(sp$decimalLongitude, digits=0),sep="_")  #sets up a variable that matches the name in Fst table
  sp<-sp[order(sp$sample),]
  # Not all localities are included in Veron's regionalization (e.g. Guam), so get their names and then zap NAs
  nonVeronpops<-unique(sp$sample[is.na(sp$VeronDivis)])
  sp<-sp[!is.na(sp$VeronDivis),]
  
  #subsample Fst 
  gslFST<-diffstats[[gsl]]
  #make a matrix out of gslFST
  gslFSTm<-as.matrix(gslFST)
  
  gslFSTm[which(gslFSTm > 1)] <- 1 #some values that look like 1.0000 are registering as greater than 1
  gslFSTm[which(gslFSTm < 0)] <- 0.0001 #get rid of artifactual negative values
  #gslFSTm<-rescale(gslFSTm)
  #gslFSTm<-gslFSTm/(1-gslFSTm)
  
  #zap weird slashes in the names
  rownames(gslFSTm)<-gsub("\"","",rownames(gslFSTm))
  colnames(gslFSTm)<-rownames(gslFSTm)
  
  #zap the same na populations from the list of non existent pops from VeronDivis
  if(any(rownames(gslFSTm) %in% nonVeronpops)){
    gslFSTm<-gslFSTm[-(which(rownames(gslFSTm) %in% nonVeronpops)),-(which(colnames(gslFSTm) %in% nonVeronpops))]
  }
  
  if(length(rownames(gslFSTm))<5){nostats<-c(nostats,gsl);cat("Fewer than 5 sampled populations");next}
  
  #and filter sp based on the localities that have Fst values
  sp<-sp[sp$sample %in% rownames(gslFSTm),]
  
  #and vice versa
  
  gslFSTm<- gslFSTm[which(rownames(gslFSTm) %in% unique(sp$sample)),which(rownames(gslFSTm) %in% unique(sp$sample))]
  
  #create a locations data frame that has all the localities plus lats and longs and their Veron region.
  locs<-as.data.frame(unique(sp$sample))
  names(locs)<-"sample"
  #locs$Long<-sp$decimalLongitude[which(locs %in% sp$sample)]
  #can't do a unique on sample, lats and longs because some samples have non-unique lats and longs! So I do a join and take the first match.
  locs<-join(locs,sp[c("sample","decimalLongitude","decimalLatitude",
                       "Bowen","Kulbicki_r","REALM")], by="sample", match="first")
  
  
  #sort gslFSTm
  gslFSTm<-gslFSTm[order(rownames(gslFSTm)),order(colnames(gslFSTm))]
  # convert to data frame with popsample names as first column
  gslFSTm<-cbind(sample=locs$sample,as.data.frame(gslFSTm))
  
  ######################################################################
  # 3. Calculate Great Circle Distance
  gcdist_km <- pointDistance(locs[,2:3],lonlat=T)/1000
  #symmetricize the matrix
  gcdist_km[upper.tri(gcdist_km)]<-t(gcdist_km)[upper.tri(gcdist_km)]
  
  #cbind on the sample names
  gcdist_km <- cbind(sample=locs$sample,as.data.frame(gcdist_km))
  
  ####################################################################
  #4. Full Model
  
  cat("Running Full Model")
  
  
  regions<-cbind(locs[,c(1,2,3)],REALM=rep_len(1,length(locs[,1])))
  if(length(unique(locs$REALM)) > 1){
    regions<-cbind(locs[,c(1,2,3)],with(locs, data.frame(model.matrix(~REALM+0))))
  }
  
  gslFSTmll<-cbind(locs[,c(2,3)],gslFSTm)
  
  gdm.format.full<-formatsitepair(bioData=gslFSTm, bioFormat=3, predData=regions,XColumn = "decimalLongitude", YColumn = "decimalLatitude", siteColumn="sample", distPreds=list(gcdist_km))
  
     #zap population pairs with 0 geographical distance between them. Troubling.
    zaps<-which(gdm.format.full$s2.matrix_1==0)
    
    if(length(zaps)>0) {
    gdm.format.full<-gdm.format.full[-zaps,]
    }
  
  # run the full model, and the model with only distance
  fullgdm<-gdm(gdm.format.full)
  distgdm<-gdm(gdm.format.full[,c(1:6,grep("matrix_1",names(gdm.format.full)))])
  
  
  #if no solution, then keep the names of the regions for this species in a matrix with zero values
  if(is.null(fullgdm) | is.null(distgdm)){
        cat("No solution obtained on Full Model")
        regions2<-regions[1,-c(1:3)]
        
        #some futzing to deal with datasets with no predictors but distance matrix
        if(length(regions2)>1){regions2[1,]<-0}
        regions2$matrix_1<-0
        regions2$Species<-gsl
        if(!is.data.frame(regions2)){regions2<-data.frame(matrix_1=0)}
        
        nosolution.full[[gsl]]<-regions2
        nosolution.list[[gsl]]<-gdm.format.full
        plot(gdm.format.full$s2.matrix_1,gdm.format.full$distance, main=gsl)
        next}
  
  # pull out stats
   #difference in deviance
    deltadev.regions<-distgdm$gdmdeviance-fullgdm$gdmdeviance
    
    #percent of null deviance explained by the model with just distance
    explaineddev.dist<-distgdm$explained
    
    gdm.regions.deviance<-fullgdm$gdmdeviance
    gdm.regions.explained<-fullgdm$explained
    gdm.no.regions.deviance<-distgdm$gdmdeviance
    gdm.no.regions.explained<-distgdm$explained
  
  ##############################################################################
    # 4A. Perform Monte-Carlo permutations to develop a null distribution 
    #    of deviance values and determine significance (pvalue)
    gdm.format.rand.full<-gdm.format.full
    rand.deltas.full<-vector() 
    rand.explained.full<-vector()
  
    while(length(rand.deltas.full) < 1000) {
      gdm.format.rand.full$distance<-sample(gdm.format.rand.full$distance,size=length(gdm.format.rand.full$distance))
      gdm.barrier.rand.full<-gdm(gdm.format.rand.full)
      gdm.no.barrier.rand.full<-gdm(gdm.format.rand.full[,c(1:6,grep("matrix_1",
                                                          names(gdm.format.rand.full)))])
    
        # if no solution obtained, go to next gsl
      if(is.null(gdm.barrier.rand.full) | is.null(gdm.no.barrier.rand.full)){next}
      
      deltadev.rand.full<-gdm.no.barrier.rand.full$gdmdeviance-gdm.barrier.rand.full$gdmdeviance
      explained.rand.full<-gdm.no.barrier.rand.full$explained
      
      rand.deltas.full<-c(rand.deltas.full,deltadev.rand.full)
      rand.explained.full<-c(rand.explained.full,explained.rand.full)
    }
    pvalue_regions.full<-length(which(abs(deltadev.regions) < abs(rand.deltas.full)))/length(rand.deltas.full)
    pvalue_dist.full<-length(which(abs(explaineddev.dist) < abs(rand.explained.full)))/length(rand.explained.full)
    
    stats.1<-c(gsl,gdm.regions.deviance,gdm.regions.explained,gdm.no.regions.deviance,gdm.no.regions.explained,deltadev.regions,pvalue_regions.full,pvalue_dist.full)
    
    stats.full[nrow(stats.full)+1,]<-stats.1
    
    gdm.full[[gsl]]<-fullgdm
    
    
}

 
 
 Now starting Acanthaster_planci_CO1 
Running Full Model
 
 
 Now starting Acanthaster_planciNIO_CR 
Running Full Model
 
 
 Now starting Acanthaster_planciPac_CR 
Running Full Model
 
 
 Now starting Acanthaster_planciRedSea_CR 

 
 
 Now starting Acanthaster_planciSIO_CR 
Fewer than 5 sampled populations
 
 
 Now starting Acanthurus_achilles_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Acanthurus_japonicus_CYB 

 
 
 Now starting Acanthurus_leucosternon_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Acanthurus_lineatus_CO1 

 
 
 Now starting Acanthurus_lineatus_CR 
Running Full ModelNo solution obtained on Full Model
 
 
 Now starting Acanthurus_nigricans_A68 

 
 
 Now starting Acanthurus_nigricans_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Acanthurus_nigrofuscus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Acanthurus_nigrofuscus_CYB 
Running Full Model
 
 
 Now starting Acanthurus_nigroris_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Acanthurus_nigros_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Acanthurus_olivaceus_CYB 
Running Full Model
 
 
 Now starting Acanthurus_sohal_CO1 
NAs in FST table, No gdm calculated
 
 
 Now starting Acanthurus_triostegus_A68 
Running Full Model
 
 
 Now starting Acanthurus_triostegus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Aipysurus_apraefrontalis_CYB 

 
 
 Now starting Aipysurus_duboisii_CYB 

 
 
 Now starting Aipysurus_eydouxii_CYB 

 
 
 Now starting Aipysurus_foliosquama_CYB 

 
 
 Now starting Aipysurus_fuscus_CYB 

 
 
 Now starting Aipysurus_laevis_CYB 

 
 
 Now starting Aipysurus_mosaicus_CYB 

 
 
 Now starting Aipysurus_pooleorum_CYB 

 
 
 Now starting Amphiprion_bicinctus_CO1 

 
 
 Now starting Amphiprion_omanensis_CO1 

 
 
 Now starting Amphiprion_perideraion_CR 
Running Full Model
 
 
 Now starting Anyperodon_leucogrammicus_CO1 

 
 
 Now starting Apogon_doederleini_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Apogon_doederleini_CR 
Fewer than 5 sampled populations
 
 
 Now starting Arothron_meleagris_A68 

 
 
 Now starting Auxis_rochei_CR 

 
 
 Now starting Auxis_thazard_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Caesio_cuning_CR 
Running Full Model
 
 
 Now starting Calotomus_carolinus_A68 

 
 
 Now starting Cantherhines_dumerilii_A68 

 
 
 Now starting Carcharhinus_sorrah_CR 
Running Full Model
 
 
 Now starting Cellana_exarata_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Cellana_sandwicensis_CO1 
Running Full Model
 
 
 Now starting Cellana_talcosa_CO1 
Running Full Model
 
 
 Now starting Centropyge_eibli_CYB 

 
 
 Now starting Centropyge_flavissima_CYB 
Running Full Model
 
 
 Now starting Centropyge_loricula_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Centropyge_vrolikii_CYB 

 
 
 Now starting Cephalopholis_argus_CO1 
Running Full Model
 
 
 Now starting Cephalopholis_argus_CYB 
Running Full Model
 
 
 Now starting Cephalopholis_cyanostigma_CO1 

 
 
 Now starting Cephalopholis_sonnerati_CO1 

 
 
 Now starting Chaetodon_auriga_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Chaetodon_auriga_CYB 
Running Full Model
 
 
 Now starting Chaetodon_collare_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Chaetodon_fremblii_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Chaetodon_leucopleura_CO1 

 
 
 Now starting Chaetodon_lunula_CO1 

 
 
 Now starting Chaetodon_melapterus_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Chaetodon_meyeri_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Chaetodon_miliaris_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Chaetodon_multicinctus_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Chaetodon_ornatissimus_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Chaetodon_trifasciatus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Chrysoblephus_puniceus_CR 
Fewer than 5 sampled populations
 
 
 Now starting Cirrhitichthys_calliurus_CO1 

 
 
 Now starting Cirrhitichthys_oxycephalus_A68 

 
 
 Now starting Cirrhitichthys_oxycephalus_CO1 

 
 
 Now starting Coryphaena_hippurus_ND1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Cromileptes_altivelis_CO1 

 
 
 Now starting Ctenochaetus_marginatus_A68 

 
 
 Now starting Ctenochaetus_striatus_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Ctenochaetus_strigosus_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Culcita_novaeguineae_CO1 
Running Full Model
 
 
 Now starting Culcita_schmideliana_CO1 

 
 
 Now starting Dascyllus_aruanus_CYB 
Running Full Model
 
 
 Now starting Dascyllus_carneus_CO1 

 
 
 Now starting Dascyllus_marginatus_CO1 

 
 
 Now starting Dascyllus_trimaculatus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Dascyllus_trimaculatus_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Dendrochirus_brachypterus_16S 

 
 
 Now starting Dendrochirus_brachypterus_CYB 

 
 
 Now starting Dendrochirus_zebra_16S 

 
 
 Now starting Dendrochirus_zebra_CYB 

 
 
 Now starting Diadema_palmeri_A68 

 
 
 Now starting Diadema_palmeri_CO1 

 
 
 Now starting Diadema_paucispinum_A68 
Fewer than 5 sampled populations
 
 
 Now starting Diadema_paucispinum_CO1 

 
 
 Now starting Diadema_savignyi_A68 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Diadema_savignyi_CO1 

 
 
 Now starting Diadema_setosum_A68 
Running Full Model
 
 
 Now starting Diadema_setosum_CO1 

 
 
 Now starting Diodon_holocanthus_A68 

 
 
 Now starting Doryrhamphus_excisus_A68 

 
 
 Now starting Echinothrix_diadema_CYB 

 
 
 Now starting Eleutheronema_tetradactylum_CO1 
Running Full Model
 
 
 Now starting Emydocephalus_annulatus_CYB 

 
 
 Now starting Ephalophis_greyi_CYB 

 
 
 Now starting Epinephelus_areolatus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Epinephelus_coeruleopunctatus_CO1 

 
 
 Now starting Epinephelus_coioides_CO1 

 
 
 Now starting Epinephelus_fasciatus_CO1 

 
 
 Now starting Epinephelus_flavocaeruleus_CO1 

 
 
 Now starting Epinephelus_longispinis_CO1 

 
 
 Now starting Epinephelus_macrospilos_CO1 

 
 
 Now starting Epinephelus_malabaricus_CO1 

 
 
 Now starting Epinephelus_marginatus_CO1 

 
 
 Now starting Epinephelus_merra_CO1 

 
 
 Now starting Epinephelus_morrhua_CO1 

 
 
 Now starting Epinephelus_multinotatus_CO1 

 
 
 Now starting Epinephelus_ongus_CO1 

 
 
 Now starting Epinephelus_poecilonotus_CO1 

 
 
 Now starting Epinephelus_polyphekadion_CO1 

 
 
 Now starting Epinephelus_spilotoceps_CO1 

 
 
 Now starting Eucidaris_metularia_CO1 

 
 
 Now starting Euthynnus_affinis_CR 
Running Full Model
 
 
 Now starting Forcipiger_flavissimus_A68 
Fewer than 5 sampled populations
 
 
 Now starting Glossogobius_callidus_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Gonodactylellus_viridis_CO1 
Running Full Model
 
 
 Now starting Halichoeres_claudia_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Halichoeres_claudia_CR 
Fewer than 5 sampled populations
 
 
 Now starting Halichoeres_hortulanus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Halichoeres_hortulanus_CR 
Running Full Model
 
 
 Now starting Halichoeres_hortulanus_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Halichoeres_margaritaceus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Halichoeres_margaritaceus_CR 
Fewer than 5 sampled populations
 
 
 Now starting Halichoeres_ornatissimus_CO1 
NAs in FST table, No gdm calculated
 
 
 Now starting Halichoeres_ornatissimus_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Halichoeres_trimaculatus_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Halichoeres_trimaculatus_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Haptosquilla_glyptocercus_CO1 
Running Full Model
 
 
 Now starting Haptosquilla_hamifera_CO1 
Running Full Model
 
 
 Now starting Haptosquilla_pulchella_CO1 
Running Full Model
 
 
 Now starting Heliocidaris_erythrogramma_CO1 

 
 
 Now starting Heliocidaris_tuberculata_CO1 

 
 
 Now starting Heteropriacanthus_cruentatus_A68 

 
 
 Now starting Himantura_leoparda_CO1 

 
 
 Now starting Himantura_tutul_CO1 

 
 
 Now starting Himantura_uarnak_CO1 

 
 
 Now starting Himantura_undulata_CO1 

 
 
 Now starting Holothuria_atra_CO1 
Running Full Model
 
 
 Now starting Holothuria_edulis_CO1 
Running Full Model
 
 
 Now starting Holothuria_whitmaei_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Hoplosquilla_said_CO1 
Running Full Model
 
 
 Now starting Hydrelaps_darwiniensis_CYB 

 
 
 Now starting Hydrophis_atriceps_CYB 

 
 
 Now starting Hydrophis_belcheri_CYB 

 
 
 Now starting Hydrophis_brooki_CYB 

 
 
 Now starting Hydrophis_caerulescens_CYB 

 
 
 Now starting Hydrophis_coggeri_CYB 

 
 
 Now starting Hydrophis_curtus_CYB 

 
 
 Now starting Hydrophis_cyanocinctus_CYB 

 
 
 Now starting Hydrophis_czeblukovi_CYB 

 
 
 Now starting Hydrophis_donaldi_CYB 

 
 
 Now starting Hydrophis_elegans_CYB 

 
 
 Now starting Hydrophis_fasciatus_CYB 

 
 
 Now starting Hydrophis_jerdoni_CYB 

 
 
 Now starting Hydrophis_lamberti_CYB 

 
 
 Now starting Hydrophis_lapemoides_CYB 

 
 
 Now starting Hydrophis_macdowelli_CYB 

 
 
 Now starting Hydrophis_major_CYB 

 
 
 Now starting Hydrophis_obscurus_CYB 

 
 
 Now starting Hydrophis_ocellatus_CYB 

 
 
 Now starting Hydrophis_ornatus_CYB 

 
 
 Now starting Hydrophis_pachycercos_CYB 

 
 
 Now starting Hydrophis_parviceps_CYB 

 
 
 Now starting Hydrophis_peronii_CYB 

 
 
 Now starting Hydrophis_platurus_CYB 

 
 
 Now starting Hydrophis_schistosus_CYB 

 
 
 Now starting Hydrophis_spiralis_CYB 

 
 
 Now starting Hydrophis_stokesii_CYB 

 
 
 Now starting Hydrophis_stricticollis_CYB 

 
 
 Now starting Hydrophis_viperinus_CYB 

 
 
 Now starting Hydrophis_zweifeli_CYB 

 
 
 Now starting Katsuwonus_pelamis_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Klyxum_simplex_ND2 

 
 
 Now starting Labroides_bicolor_CR 

 
 
 Now starting Labroides_dimidiatus_CR 
Running Full Model
 
 
 Now starting Labroides_pectoralis_CR 

 
 
 Now starting Linckia_laevigata_CO1 
Running Full Model
 
 
 Now starting Lobophytum_pauciflorum_ND2 

 
 
 Now starting Lutjanus_decussatus_CO1 

 
 
 Now starting Lutjanus_fulvus_CYB 
Running Full Model
 
 
 Now starting Lutjanus_kasmira_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Lutjanus_kasmira_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Microcephalophis_gracilis_CYB 

 
 
 Now starting Mulloidichthys_flavolineatus_A68 

 
 
 Now starting Mulloidichthys_flavolineatus_CR 

 
 
 Now starting Mulloidichthys_mimicus_A68 

 
 
 Now starting Mulloidichthys_mimicus_CR 

 
 
 Now starting Mulloidichthys_pflugeri_A68 

 
 
 Now starting Mulloidichthys_vanicolensis_A68 

 
 
 Now starting Mulloidichthys_vanicolensis_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Myripristis_berndti_A68 

 
 
 Now starting Myripristis_earlei_A68 

 
 
 Now starting Naso_brevirostris_CR 
Running Full Model
 
 
 Now starting Naso_caesius_CO1 

 
 
 Now starting Naso_caesius_CR 

 
 
 Now starting Naso_hexacanthus_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Naso_hexacanthus_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Naso_unicornis_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Negaprion_acutidens_CR 
Fewer than 5 sampled populations
 
 
 Now starting Negaprion_brevirostris_CR 
Fewer than 5 sampled populations
 
 
 Now starting Neoniphon_sammara_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Neoniphon_sammara_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Nerita_albicilla_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Nerita_plicata_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Novaculichthys_taeniourus_A68 

 
 
 Now starting Ostracion_meleagris_A68 

 
 
 Now starting Panulirus_interruptus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Panulirus_marginatus_CO2 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Panulirus_penicillatus_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Parahydrophis_mertoni_CYB 

 
 
 Now starting Parapenaeopsis_coromandelica_CO1 

 
 
 Now starting Penaeus_indicus_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Periclimenes_soror_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Plectorhinchus_chaetodonoides_CO1 

 
 
 Now starting Plectropomus_leopardus_CO1 

 
 
 Now starting Plectropomus_maculatus_CO1 

 
 
 Now starting Polydactylus_macrochir_CR 
Running Full Model
 
 
 Now starting Pomacentrus_coelestis_CO1 
Running Full Model
 
 
 Now starting Pomacentrus_coelestis_CR 
Running Full Model
 
 
 Now starting Pomacentrus_micronesicus_CO1 

 
 
 Now starting Pomacentrus_micronesicus_CR 

 
 
 Now starting Pristipomoides_filamentosus_CYB 
NAs in FST table, No gdm calculated
 
 
 Now starting Protoreaster_nodosus_CO1 
Running Full Model
 
 
 Now starting Pseudoboletia_indiana_CO1 

 
 
 Now starting Pseudoboletia_maculata_CO1 

 
 
 Now starting Pterois_antennata_16S 

 
 
 Now starting Pterois_antennata_CYB 

 
 
 Now starting Pterois_miles_16S 

 
 
 Now starting Pterois_miles_CYB 

 
 
 Now starting Pterois_mombasae_16S 

 
 
 Now starting Pterois_mombasae_CYB 

 
 
 Now starting Pterois_radiata_16S 

 
 
 Now starting Pterois_radiata_CYB 

 
 
 Now starting Pterois_volitans_16S 

 
 
 Now starting Pterois_volitans_CR 
Fewer than 5 sampled populations
 
 
 Now starting Pterois_volitans_CYB 

 
 
 Now starting Pygoplites_diacanthus_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Pygoplites_diacanthus_CYB 
Fewer than 5 sampled populations
 
 
 Now starting Rastrelliger_kanagurta_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Rhincodon_typus_CR 
Fewer than 5 sampled populations
 
 
 Now starting Sarcophyton_trocheliophorum_ND2 

 
 
 Now starting Scarus_ghobban_A68 

 
 
 Now starting Scarus_psittacus_CR 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Scarus_rubroviolaceus_A68 

 
 
 Now starting Scomberomorus_commerson_CR 
Running Full Model
 
 
 Now starting Scomberomorus_sp_CR 

 
 
 Now starting Sectator_ocyurus_A68 

 
 
 Now starting Sepioteuthis_lessonianaSPA_CO1 
Fewer than 5 sampled populations
 
 
 Now starting Sepioteuthis_lessonianaSPB_CO1 

 
 
 Now starting Sepioteuthis_lessonianaSPC_CO1 
Running Full Model
 
 
 Now starting Siamosquilla_laevicaudata_CO1 
Running Full Model
 
 
 Now starting Siganus_fuscescens_CR 
Running Full Model
 
 
 Now starting Sinularia_densa_ND2 

 
 
 Now starting Sinularia_peculiaris_ND2 

 
 
 Now starting Sphyraena_barracuda_CYB 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Sphyrna_lewini_CR 
Running Full Model
 
 
 Now starting Stenella_longirostris_CR 
Running Full Model
 
 
 Now starting Stenella_longirostris_CYB 
Running Full Model
 
 
 Now starting Stenopus_hispidus_CO1 
NAs in FST table, No gdm calculated
 
 
 Now starting Stethojulis_bandanensis_A68 

 
 
 Now starting Thor_amboinensis_CO1 
Running Full ModelNo solution obtained on Full Model


 
 
 Now starting Thunnus_albacares_CO1 

 
 
 Now starting Thyca_crystallina_CO1 
Running Full Model
 
 
 Now starting Tridacna_costata_CO1 
Running Full Model
 
 
 Now starting Tridacna_crocea_16S 

 
 
 Now starting Tridacna_crocea_CO1 
Running Full Model
 
 
 Now starting Tridacna_maxima_16S 

 
 
 Now starting Tridacna_maxima_CO1 
Running Full Model
 
 
 Now starting Tridacna_ningaloo_CO1 

 
 
 Now starting Tridacna_sp_16S 

 
 
 Now starting Tridacna_squamosa_16S 

 
 
 Now starting Tridacna_squamosa_CO1 
Running Full Model
 
 
 Now starting Tripneustes_gratilla_CO1 
NAs in FST table, No gdm calculated
 
 
 Now starting Xenia_sp_ND2 

 
 
 Now starting Zanclus_cornutus_A68 

 
 
 Now starting Zebrasoma_flavescens_CYB 
Running Full ModelNo solution obtained on Full Model

Create a heatmap from GDM regions

dbRDA


# read in the Fst/PhiSt table 
load("~/google_drive/DIPnet_Gait_Lig_Bird/DIPnet_WG4_first_papers/statistics/By_Species/Pairwise_statistics/sample/DIPnet_structure_sample_WCTheta.Rdata")
#load("~/Desktop/DIPnet_structure_sample_PhiST_042817.Rdata")


##1. Dataframe for results
stats<-data.frame(Species_Locus=character(0),constrained.inertia=numeric(0),totalInertia=numeric(0),ProportionConstrained=numeric(0),adj.R2.total=numeric(0),modelF=numeric(0),modelPvalue=numeric(0),pcx_Var=numeric(0),pcx_p=numeric(0),pcy_Var=numeric(0),pcy_p=numeric(0),bestmodel=character(0), constrained.inertia.best=numeric(0), total.inertia.best=numeric(0), proportion.constrained.inertia.best=numeric(0), adj.R2.best.model=numeric(0), stringsAsFactors = F)
stats$Species_Locus<-as.character(stats$Species_Locus)
#stats$Barrier<-as.character(stats$Barrier)
stats$bestmodel<-as.character(stats$bestmodel)

# Make an empty list to save rda output for each species
esu_loci <- unique(ipdb$Genus_species_locus)
all.gsl.rda<-sapply(esu_loci, function(x) NULL)

#make empty data frames to save variance and pvalues
term.vars<-data.frame(gsl=character(0))
term.pvals<-data.frame(gsl=character(0))

###############################################################################
# 2. Subsample for each species of interest, and filter based on Phi_ST table.
for(gsl in esu_loci){ #gsl<-"Linckia_laevigata_CO1" "Tridacna_crocea_CO1" "Lutjanus_kasmira_CYB"
  
  cat("\n","\n","\n","Now starting", gsl, "\n")
  
  if(any(is.na(diffstats[[gsl]]))){cat("NAs in FST table, No dbRDA calculated"); next}
  
  if(diffstats[[gsl]]=="Fewer than 3 sampled populations after filtering. No stats calculated"){all.gsl.rda[[gsl]]<-"Fewer than 5 sampled populations after filtering."; cat("Fewer than 5 sampled populations after filtering.");next}
   sp<-ipdb[which(ipdb$Genus_species_locus==gsl),]
  
  #clean weird backslashes from names
  sp$locality<-gsub("\"","",sp$locality)
  
  sp$sample<-paste(sp$locality,round(sp$decimalLatitude, digits=0),round(sp$decimalLongitude, digits=0),sep="_")  #sets up a variable that matches the name in Fst table
  sp<-sp[order(sp$sample),]
  # Not all localities are included in Veron's regionalization (e.g. Guam), so get their names and then zap NAs
  nonVeronpops<-unique(sp$sample[is.na(sp$VeronDivis)])
  sp<-sp[!is.na(sp$VeronDivis),]
  
  #subsample Fst 
  gslFST<-diffstats[[gsl]]
  #make a matrix out of gslFST, convert negative values to zero
  gslFSTm<-as.matrix(gslFST)
  gslFSTm[which(gslFSTm<0)]<-0.0
  
  #zap weird slashes in the names
  rownames(gslFSTm)<-gsub("\"","",rownames(gslFSTm))
  colnames(gslFSTm)<-rownames(gslFSTm)
  
  #zap the same na populations from the list of non existent pops from VeronDivis
  if(any(rownames(gslFSTm) %in% nonVeronpops)){
    gslFSTm<-gslFSTm[-(which(rownames(gslFSTm) %in% nonVeronpops)),-(which(colnames(gslFSTm) %in% nonVeronpops))]
  }
  if(length(rownames(gslFSTm))<5){all.gsl.rda[[gsl]]<-"Fewer than 5 sampled populations";cat("Fewer than 5 sampled populations");next}
  
  #and filter sp based on the localities that have Fst values
  sp<-sp[sp$sample %in% rownames(gslFSTm),]
  
  #and vice versa
  
  gslFSTm<- gslFSTm[which(rownames(gslFSTm) %in% unique(sp$sample)),which(rownames(gslFSTm) %in% unique(sp$sample))]
  

  if(length(rownames(gslFSTm))<5){all.gsl.rda[[gsl]]<-"Fewer than 5 sampled populations";cat("Fewer than 5 sampled populations");next}
  
  #create a locations data frame that has all the localities plus lats and longs and their Veron region.
  locs<-as.data.frame(unique(sp$sample))
  names(locs)<-"sample"
  #locs$Long<-sp$decimalLongitude[which(locs %in% sp$sample)]
  #can't do a unique on sample, lats and longs because some samples have non-unique lats and longs! So I do a join and take the first match.
  locs<-join(locs,sp[c("sample","decimalLongitude","decimalLatitude"
                       ,"VeronDivis")], by="sample", match="first")
  if (length(unique(locs$VeronDivis)) < 2) {"Only one region!"; cat("Only one region!"); next}
  
  #sort gslFSTm
  gslFSTm<-gslFSTm[order(rownames(gslFSTm)),order(colnames(gslFSTm))]

  
  ######################################################################
  # 4. Calculate Great Circle Distance
  gcdist_km <- pointDistance(locs[,2:3],lonlat=T)/1000
  # and symmetricise it
  gcdist_km[upper.tri(gcdist_km)]<-0
  gcdist_km<-gcdist_km + t(gcdist_km)
   
  ####################################################################### Calculate Overwater Distances#
  #Save for later##

  ##############################################################################
  #5. Create a matrix of regional identities
  
  regions<-with(locs, data.frame(model.matrix(~VeronDivis+0)))   #one of the predictors is superfluous but will get knocked out during RDA
  row.names(regions)<-row.names(locs)
  

    ############################################################################
    # 7. Calculate the principal coordinates
    
    FST.pcoa<-cmdscale(gslFSTm, k=dim(as.matrix(gslFSTm))[1] - 1, eig=TRUE, add=FALSE) #ignore warnings - OK to have negatives according to Anderson
    FST.scores<-FST.pcoa$points
    
    gcdist.pcoa<-cmdscale(gcdist_km, k=2, eig=TRUE, add=FALSE)
    gcdist.scores<-gcdist.pcoa$points
    gcdist.scores<-data.frame("pcx"=gcdist.pcoa$points[,1],"pcy"=gcdist.pcoa$points[,2])
    locs2<-cbind(regions,gcdist.scores)
    
    ###########################################################################
    # 8. Calculate the RDA and extract statistics
    RDA.res<-rda(FST.scores~., data=locs2, scale=TRUE )
    
    #Extract Statistics
    constrained.inertia<-summary(RDA.res)$constr.chi
    total.inertia<-summary(RDA.res)$tot.chi
    proportion.constrained.inertia<-constrained.inertia/total.inertia
    
    adj.R2.total.model<-RsquareAdj(RDA.res)$adj.r.squared
    if(is.na(adj.R2.total.model)){cat("Predictors >= Observations! No solution");all.gsl.rda[[gsl]]<-"Predictors >= Observations! No solution";next}
    
    model.sig<-anova.cca(RDA.res, step=1000)
    modelF<-model.sig$F[1]
    modelPvalue<-model.sig$`Pr(>F)`[1]
    
    terms.sig<-anova(RDA.res, by="term", step=1000)
    pcx_Var<-terms.sig$Variance[1]
    pcx_p<-terms.sig$`Pr(>F)`[1]
    pcy_Var<-terms.sig$Variance[2]
    pcy_p<-terms.sig$`Pr(>F)`[2]
    
    #extract all variance values into a dataframe
    term.var<-as.data.frame(t(terms.sig[,2]))
    names(term.var)<-rownames(terms.sig)
   
    #extract all p-values into a dataframe
    term.pval<-as.data.frame(t(terms.sig[,4]))
    names(term.pval)<-rownames(terms.sig)
    
     
    # scale the variance
    term.var<-term.var/sum(term.var)
    
    # set variance to zero if it is not significant
    term.var[1,which(term.pval[1,] > 0.05 | is.na(term.pval[1,]))]<-0
    
    #set all values to zero if the model itself is not significant
    if(modelPvalue > 0.05){
    term.var[1,which(names(term.var)!="gsl")]<-0
    }
    # add on the species name
    term.pval$gsl<-gsl
    term.var$gsl<-gsl
    
    #merge them on to each dataframe
    term.vars<-merge(term.vars,term.var,all=T)
    term.pvals<-merge(term.pvals,term.pval,all=T)
    
    
    
    #barrier_Var<-terms.sig$Variance[3]   #omitting for now as the number of barriers will differ
    #barrier_p<-terms.sig$`Pr(>F)`[3]
    
    #marg.sig<-anova(RDA.res, by="margin", step=1000)
    #barrier_margVar<-marg.sig$Variance[3]
    #barrier_margp<-marg.sig$`Pr(>F)`[3]
    
    #Model selection
    nullmodel<-rda(FST.scores~1, data=locs2, scale=TRUE )
    forward.model<-ordiR2step(nullmodel, scope=formula(RDA.res), directon="forward", psteps=1000)  #ordiR2step implements Blanchets stopping criterion
    bestmodel<-as.character(forward.model$call[2])
    if (is.null(summary(forward.model)$constr.chi)) {
      constrained.inertia.best<-NA
      total.inertia.best<-summary(forward.model)$tot.chi
      proportion.constrained.inertia.best<-NA
      adj.R2.best.model<-NA
    } else {
      constrained.inertia.best<-summary(forward.model)$constr.chi
      total.inertia.best<-summary(forward.model)$tot.chi
      proportion.constrained.inertia.best<-constrained.inertia.best/total.inertia.best
      adj.R2.best.model<-RsquareAdj(forward.model)$adj.r.squared
    }
     
  
    #save stats
    
    stats_model<-c(gsl,constrained.inertia,total.inertia,proportion.constrained.inertia,adj.R2.total.model,modelF,modelPvalue,pcx_Var,pcx_p,pcy_Var,pcy_p, bestmodel, constrained.inertia.best, total.inertia.best, proportion.constrained.inertia.best, adj.R2.best.model)
    
    stats[nrow(stats)+1,]<-stats_model
    all.gsl.rda[[gsl]]<-RDA.res
    
    
 
  }

write.csv(term.vars,file="./output/dbRDA_term_vars_WCTHETA.csv")
write.csv(term.pvals,file="./output/dbRDA_term_pvals_WCTHETA.csv")

 save(all.gsl.rda,file="./output/multibarrier_dbRDA_WCTHETA.Rdata")
  
write.csv(stats, "./output/multibarrier_dbRDA_JOSTD.csv")
  

Make a heatmap of the variance values

LS0tCnRpdGxlOiAiRElQbmV0IFBvcHVsYXRpb24gU3RydWN0dXJlIE5vdGVib29rIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwotLS0KCiMgU2V0dXAKYGBge3IgU2V0dXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoc2VxaW5yKQpsaWJyYXJ5KGFwZSkgIApsaWJyYXJ5KHBlZ2FzKQpsaWJyYXJ5KGhpZXJmc3RhdCkKbGlicmFyeShtbW9kKQpsaWJyYXJ5KGFkZWdlbmV0KQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoc3RyYXRhRykKbGlicmFyeShpTkVYVCkKbGlicmFyeShnZG0pCmxpYnJhcnkoZ2Rpc3RhbmNlKQpsaWJyYXJ5KGVjb2Rpc3QpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoV3JpdGVYTFMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrbml0cikKbGlicmFyeSh2ZWdhbikKCgpzb3VyY2UoImNvbmZpZy5SIikKc291cmNlKCJESVBuZXRfU3RhdHNfRnVuY3Rpb25zLlIiKQoKcmVzY2FsZTwtZnVuY3Rpb24oeCl7CiAgbm9ybWFsaXplZDwtKHgtbWluKHgpKS8obWF4KHgpLW1pbih4KSkKICByZXR1cm4obm9ybWFsaXplZCkKfQoKYGBgCgpgYGB7ciBJbXBvcnQgRGF0YX0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIDEuIEltcG9ydCB0aGUgSVBEQiBhbmQgRnN0IHRhYmxlcwppcGRiPC1yZWFkLnRhYmxlKGlwZGJfcGF0aCxzZXA9Ilx0IixoZWFkZXI9VCxzdHJpbmdzQXNGYWN0b3JzID0gRixxdW90ZT0iIiwgbmEuc3RyaW5ncz1jKCJOQSIsIiAiLCIiKSkgCgoKI3JlYWQgaW4gZ2VvZ3JhcGhpY2FsIHJlZ2lvbmFsaXphdGlvbnMgZnJvbSBUcmVtbApzcGF0aWFsPC1yZWFkLnRhYmxlKHNwYXRpYWxfcGF0aCwgaGVhZGVyPVQsIHNlcD0iXHQiLHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBuYS5zdHJpbmdzPWMoIk5BIiwiICIsIiIpLCBxdW90ZT0iIikKCiNyZWFkIGluIGdlb2dyYXBoaWNhbCByZWdpb25hbGl6YXRpb25zIGZyb20gQmVnZXIKc3BhdGlhbDI8LXJlYWQudGFibGUoc3BhdGlhbDJfcGF0aCwgaGVhZGVyPVQsc2VwPSJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBuYS5zdHJpbmdzPWMoIk5BIiwiICIsIiIpLCBxdW90ZT0iIikKCiNyZWFkIGluIEFCR0QgZ3JvdXBzCmFiZ2Q8LXJlYWQudGFibGUoYWJnZF9wYXRoLCBoZWFkZXI9VCwgc2VwPSJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKI2pvaW4gc3BhdGlhbAppcGRiPC1qb2luKGlwZGIsc3BhdGlhbCwgYnkgPSAiSVBEQl9JRCIsdHlwZSA9ICJsZWZ0IikKaXBkYjwtam9pbihpcGRiLHNwYXRpYWwyWyxjKDIsMTg6MjQpXSwgYnkgPSAiSVBEQl9JRCIsIHR5cGUgPSAibGVmdCIpCgojam9pbiBBQkdECmlwZGI8LWpvaW4oaXBkYixhYmdkWyxjKDEsMyldLCBieSA9ICJJUERCX0lEIix0eXBlID0gImxlZnQiKQoKIyBkcm9wIGh5YnJpZHMgYW5kIGRpdmVyZ2VudCBpbmRpdmlkdWFscwppcGRiPC1pcGRiW2lwZGIkSVBEQl9JRCAlaW4lIGRyb3BzID09IEZBTFNFLCBdIAoKCgojIyByZW1vdmUgYW55dGhpbmcgbm90IGluY2x1ZGVkIGluIHRoZSBlY29yZWdpb25zIHNjaGVtZSAoc29tZSBkb2xwaGlucywgc29tZSBDT1RTIGZyb20gS2luZ21hbiBhbmQgTWFkYWdhc2Nhcig/KSwgc29tZSBBLiBuaWdyb3MgZnJvbSBLaXJpYmF0aSwgc29tIEMuIGF1cmlnYSBmcm9tIEZha2FyZXZhLCBoYW1tZXJoZWFkcyBmcm9tIFdlc3Rlcm4gQXVzdHJhbGlhLCBhbmQgV2VzdCBBZnJpY2EsIGFuZCBzb21lIGRvbHBoaW5zIGZyb20gdGhlIG1pZGRsZSBvZiB0aGUgZWFzdGVybiB0cm9waWNhbCBwYWNpZmljCgppcGRiX2Vjb3JlZ2lvbnM8LWlwZGJbLXdoaWNoKGlzLm5hKGlwZGIkRUNPUkVHSU9OKSksXQoKIyMgcmVtb3ZlIGFueXRoaW5nIHRoYXQgZG9lc24ndCBvY2N1ciBpbiB0aGUgMyBJbmRvLVBhY2lmaWMgcmVhbG1zCmlwZGJfaXA8LWlwZGJfZWNvcmVnaW9uc1t3aGljaChpcGRiX2Vjb3JlZ2lvbnMkUkVBTE0gJWluJSBjKCJDZW50cmFsIEluZG8tUGFjaWZpYyIsIldlc3Rlcm4gSW5kby1QYWNpZmljIiwiRWFzdGVybiBJbmRvLVBhY2lmaWMiKSksXQoKYW1vdmFfdHNfcGF0aDwtIi9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X1NwZWNpZXMvSGllcmFyY2hpY2FsX3N0cnVjdHVyZSIKCmFtb3ZhX2FiZ2RfcGF0aDwtIi9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X0VTVS9IaWVyYXJjaGljYWxfc3RydWN0dXJlIgoKIyBSZWFkIGluIFZlcm9uIGJhcnJpZXJzCmJhcnJpZXJzPC1yZWFkLmNzdigiVmVyb25CYXJyaWVycy5jc3YiLGhlYWRlcj1GLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKCgpgYGAKCgojIEludHJvZHVjdGlvbgoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIEkgYW0gdHJ5aW5nIGl0IG91dCBhcyBhIHdheSB0byByZXByb2R1Y2libHkgZG9jdW1lbnQgbXkgd29yayBvbiB0aGUgRElQbmV0IFBvcHVsYXRpb24gU3RydWN0dXJlIFBhcGVyLgoKVGhlIG92ZXJhbGwgd29ya2Zsb3cgZm9yIHRoaXMgYW5hbHlzaXMgaXMgYXMgZm9sbG93czoKCiAgLSBSdW4gQU1PVkEgYWNjb3JkaW5nIHRvIHNldmVyYWwgZGlmZmVyZW50IHJlZ2lvbmFsaXphdGlvbnMKICAgIC0gQnJpZ2dzIGFuZCBCb3dlbiAyMDEzIC0gRmlzaCBCaW9nZW9ncmFwaHkKICAgIC0gVmVyb24gZXQgYWwuIDIwMTUgLSBDb3JhbCBCaW9nZW9ncmFwaHkKICAgIC0gU3BhbGRpbmcgZXQgYWwuIDIwMDcgLSAKICAgICAgICAtIE1hcmluZSBFY29yZWdpb25zCiAgICAgICAgLSBQcm92aW5jZXMKICAgICAgICAtIFJlYWxtcwogICAgLSBLdWxiaWNraSBldCBhbC4gMjAxMyAtIAogICAgICAgIC0gUmVnaW9uYWxpemF0aW9uIGJhc2VkIG9uIGFsbCBzcGVjaWVzLCAKICAgICAgICAtIG9yIGp1c3QgInJlbGlhYmxlIiBzcGVjaWVzCiAgICAtIEtlaXRoIGV0IGFsLiAyMDEzIC0gRmF1bmFsIEJyZWFrcwogIC0gU2VsZWN0IHRoZSBiZXN0IG1vZGVsIGZvciBlYWNoIHNwZWNpZXMgYWNjb3JkaW5nIHRvIHRoZSBCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24KICAtIEFuYWx5emUgaW5kaXZpZHVhbCAiYmFycmllcnMiIGFzIGltcGxpZWQgYnkgdGhlIHJlZ2lvbmFsaXphdGlvbiB0aGF0IGJlc3QgZXhwbGFpbnMgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YXJpYXRpb24gaW4gdGhlIG1vc3Qgc3BlY2llcyBieSBtb2RlbGluZyBwYWlyd2lzZSBnZW5ldGljIGRpc3RhbmNlcyBnaXZlbiBnZW9ncmFwaGljIGRpc3RhbmNlIGFuZCBlYWNoIGJhcnJpZXIgKGluZGl2aWR1YWxseSBvciB0b2dldGhlcik6CiAgICAtIEdlbmVyYWxpemVkIERpc3NpbWlsYXJpdHkgTW9kZWxpbmcgKEdETSkKICAgIC0gTXVsdGlwbGUgUmVncmVzc2lvbiB3aXRoIERpc3RhbmNlIE1hdHJpY2VzIChNUkRNKQogICAgLSBEaXN0YW5jZSBCYXNlZCBSZWR1bmRhbmN5IEFuYWx5c2lzIChkYlJEQSkKICAtIFNwZWNpYWwgY29uc2lkZXJhdGlvbnM6CiAgICAtIFdoYXQgaXMgYSBzcGVjaWVzPyBEbyB0aGUgYW5hbHlzaXMgdXNpbmc6CiAgICAgICAgLSBUcmFkaXRpb25hbCBzcGVjaWVzIGJvdW5kYXJpZXMKICAgICAgICAtIEF1dG9tYXRlZCBCYXJjb2RlIEdhcCBEaXNjb3ZlcnkgKEFCR0QpIHRvIGFjY291bnQgZm9yIGNyeXB0aWMgc3BlY2llcwogICAgLSBJbmNsdWRlIHNlcXVlbmNlIGRpc3RhbmNlIGluIEFNT1ZBPwogICAgICAgIC0gTm86IHRyYWRpdGlvbmFsIEZzdCwgc3BlY2lmaWNhbGx5IFdlaXIgYW5kIENvY2tlcmhhbXMgVGhldGEKICAgICAgICAtIFllczogUGhpLVNUCgojIFJ1biBBTU9WQSBsb29wcwoKR2l2ZW4gdGhlIHNwZWNpYWwgY29uc2lkZXJhdGlvbnMsIHdlIG5lZWQgdG8gcnVuIDQgZGlmZmVyZW50IGZsYXZvcnMgb2YgQU1PVkE6CiAgMS4gV0NUaGV0YSBhbmQgVHJhZFNwZWMKICAyLiBXQ1RoZXRhIGFuZCBBQkdECiAgMy4gUGhpU1QgYW5kIFRyYWRTcGVjCiAgNC4gUGhpU1QgYW5kIEFCR0QKClRodXMsIHdlIG5lZWQgdG8gbG9vcCB0aHJvdWdoIGFsbCBvZiB0aGUgcmVnaW9uYWxpemF0aW9ucyBhYm92ZSwgcnVubmluZyBhbGwgNCBmbGF2b3JzIG9mIEFNT1ZBLgoKCmBgYHtyIEFNT1ZBIExvb3BzLCBldmFsPUZ9CgojIyBMb29wIHRocm91Z2ggaHlwb3RoZXNlcywgY2FsY3VsYXRpbmcgQU1PVkEKaHlwb3RoZXNlczwtYygiRUNPUkVHSU9OIiwgIlBST1ZJTkNFIiwiUkVBTE0iLCJCb3dlbiIsIktlaXRoIiwiS3VsYmlja2lfciIsIkt1bGJpY2tpX2IiLCAiVmVyb25EaXZpcyIpCmFtb3ZhX2xpc3Q8LWxpc3QoKQoKZm9yKGggaW4gaHlwb3RoZXNlcyl7CiAgaGllcnN0YXRzPC1oaWVyYXJjaGljYWwuc3RydWN0dXJlLm10RE5BLmRiKGlwZGIgPSBpcGRiX2lwLGxldmVsMSA9ICJzYW1wbGUiLGxldmVsMj1oLG1vZGVsPSJyYXciLEFCR0Q9RixucGVybT0xKQogIGFtb3ZhX2xpc3RbW2hdXTwtaGllcnN0YXRzCn0KICAKI2xvYWQoZmlsZS5wYXRoKGFtb3ZhX3RzX3BhdGgsIlBISVNUX1RyYWRTcGVjaWVzX3Jhd19hbW92YV9vdXRwdXQuUmRhdGEiKSkKIyMgU3VtbWFyaXplIEFNT1ZBIHJlc3VsdHMKYW1vdmFzdGF0czwtc3VtbWFyaXplX0FNT1ZBKGFtb3ZhX2xpc3QsaHlwb3RoZXNlcyxzcGVjaWVzbGlzdD11bmlxdWUoaXBkYiRHZW51c19zcGVjaWVzX2xvY3VzKSkKCldyaXRlWExTKGFtb3Zhc3RhdHMsRXhjZWxGaWxlTmFtZT1maWxlLnBhdGgoYW1vdmFfdHNfcGF0aCwiUEhJU1RfdHNfcmF3X3RhYmxlX2Ftb3ZhX291dHB1dC5SZGF0YS54bHN4Iikscm93Lm5hbWVzID0gVCkKc2F2ZShhbW92YV9saXN0LGZpbGU9ZmlsZS5wYXRoKGFtb3ZhX2FiZ2RfcGF0aCwiRlNUX2FiZ2RfcmF3X2Ftb3ZhX291dHB1dC5SZGF0YSIpKQpzYXZlKGFtb3Zhc3RhdHMsZmlsZT1maWxlLnBhdGgoYW1vdmFfYWJnZF9wYXRoLCJGU1RfYWJnZF90YWJsZV9hbW92YV9vdXRwdXQuUmRhdGEiKSkKYGBgCgoKVGhpcyB0YWtlcyBhIGxvbmcgdGltZSwgc28gd2UgYXJlIG5vdCBydW5uaW5nIHRoaXMgY29kZSBpbiB0aGUgZG9jdW1lbnQsIGJ1dCBsb2FkaW5nIGluIHRoZSByZXN1bHRzIGFzIHdlIGdvIHRocm91Z2ggZWFjaCBjb25zaWRlcmF0aW9uCgojIFZpc3VhbGl6ZSBBTU9WQSByZXN1bHRzCgojIyBGU1QgYW5kIFRyYWRpdGlvbmFsIFNwZWNpZXMgQm91bmRhcmllcwoKIyMjIE1lYXN1cmUgU3VwcG9ydApgYGB7ciBNZWFzdXJlIFN1cHBvcnQxfQpsb2FkKGZpbGU9ZmlsZS5wYXRoKGFtb3ZhX3RzX3BhdGgsIkZTVF9UcmFkU3BlY190YWJsZV9hbW92YV9vdXRwdXQuUmRhdGEiKSkKCiMgTWVhc3VyZSBzdXBwb3J0IGZvciBlYWNoIGh5cG90aGVzaXMKCiNHZXQgdGhlIHZhbHVlcyBmb3IgZWFjaCBoeXBvdGhlc2lzIGZvciBhIGdpdmVuIGNyaXRlcmlvbiAtIGhlcmUgSSB1c2UgQklDIC0gYW5kIHJhbmsgdGhlbSBmb3IgI2VhY2ggc3BlY2llcywgdGhlbiBjaG9vc2UgdGhlICJiZXN0IiBoeXBvdGhlc2lzIGZvciBlYWNoIHNwZWNpZXMgYmFzZWQgb24gdGhlIGNyaXRlcmlvbi4KCmNyaXRlcmlvbjwtIkJJQyIKIyBmaW5kIHRoZSBtYXhpbXVtIG51bWJlciBvZiBzcGVjaWVzIGZyb20gYW55IG9mIHRoZSA4IGh5cG90aGVzZXMKbWF4bGVuZ3RoPC1tYXgoc2FwcGx5KGFtb3Zhc3RhdHMsZnVuY3Rpb24oeCkgbGVuZ3RoKHhbWzFdXSkpKSAKIyBjcmVhdGUgYW4gZW1wdHkgZGF0YSBmcmFtZSB3aXRoIHJvdyBuYW1lcyBmcm9tIHRoZSBoeXBvdGhlc2lzIHdpdGggdGhlIG1vc3QgdmFsdWVzCmNyaXRfZGY8LWRhdGEuZnJhbWUoc2V0TmFtZXMocmVwbGljYXRlKG1heGxlbmd0aCxudW1lcmljKDApLCBzaW1wbGlmeSA9IEYpLG5tPXJvdy5uYW1lcyhhbW92YXN0YXRzW1siUFJPVklOQ0UiXV0pKSkgCgojTG9vcCB0aHJvdWdoIHRoZSBoeXBvdGhlc2VzLCBwdWxsaW5nIG91dCB0aGUgdmFsdWVzIGZvciBjcml0ZXJpb24sdHJhbnNwb3NlIGl0LCBhbmQgdGhlbiBtZXJnZSB0aGVzZSB2YWx1ZXMgaW50byB0aGUgZGF0YWZyYW1lIGZyb20gdGhlIHByZXZpb3VzIGh5cG90aGVzaXMgCmZvcihoIGluIG5hbWVzKGFtb3Zhc3RhdHMpKXsKICBjcml0X2RmPC1tZXJnZShjcml0X2RmLHQoYW1vdmFzdGF0c1tbaF1dW2NyaXRlcmlvbl0pLGFsbD1ULHNvcnQ9RikKfQojZ2V0IHRoZSBoeXBvdGhlc2lzIG5hbWVzIGluIHRoZXJlCnJvdy5uYW1lcyhjcml0X2RmKTwtbmFtZXMoYW1vdmFzdGF0cykKCiNyYW5rIHRoZSBoeXBvdGhlc2VzIGZvciBlYWNoIHNwZWNpZXMKY3JpdF9yYW5rPC1hcy5kYXRhLmZyYW1lKHNhcHBseShjcml0X2RmLHJhbmssbmEubGFzdD0ia2VlcCIsdGllcy5tZXRob2Q9ImF2ZXJhZ2UiKSkKcm93Lm5hbWVzKGNyaXRfcmFuayk8LW5hbWVzKGFtb3Zhc3RhdHMpCgojIyByZW1vdmUgZ3NscyB3aXRoIG1vcmUgdGhhbiAzIG1pc3NpbmcgbW9kZWxzCmNyaXRfcmFuazwtY3JpdF9yYW5rWywgY29sU3Vtcyhpcy5uYShjcml0X3JhbmspKSA8IG5yb3coY3JpdF9yYW5rKS01XSAgCgojIyBjaG9vc2UgdGhlIGJlc3QgaHlwb3RoZXNpcyBvciBzZXQgb2YgaHlwb3RoZXNlcyBmb3IgZWFjaCBzcGVjaWVzICAKYmVzdF9oeXBvdGhlc2lzPC1zYXBwbHkoY3JpdF9yYW5rLGZ1bmN0aW9uKHgpe3Jvdy5uYW1lcyhjcml0X3JhbmspW3doaWNoKHg9PW1pbih4LG5hLnJtPVQpKSBdfSkKCgojIyBNYWtlIGEgYmFyIGdyYXBoIG9mIGJlc3Qgc3VwcG9ydCBmb3IgZWFjaCBoeXBvdGhlc2lzIGFtb25nIHNwZWNpZXMKCmJhcnBsb3Q8LWdncGxvdChkYXRhPWFzLmRhdGEuZnJhbWUodW5saXN0KGJlc3RfaHlwb3RoZXNpcykpLCBhZXMoeD11bmxpc3QoYmVzdF9oeXBvdGhlc2lzKSApKSArIGdlb21fYmFyKGFlcyh5ID0gKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpKSArIGxhYnMoeD0iSHlwb3RoZXNpcyIseT0iUHJvcG9ydGlvbiBvZiBTcGVjaWVzIiwgdGl0bGU9IlByb3BvcnRpb25hbCBTdXBwb3J0IGZvciBCaW9nZW9ncmFwaGljIEh5cG90aGVzZXMgYmFzZWQgb24gQklDIikKCmJhcnBsb3QKYGBgCgojIyMgQ2FsY3VsYXRlIHJlbGF0aXZlIHByb2JhYmlsaXR5IGZyb20gSm9obnNvbiBhbmQgT21sYW5kIDIwMDQgYW5kIHZpc3VhbGl6ZSB3aXRoIGEgaGVhdG1hcApgYGB7ciBSZWxhdGl2ZSBQcm9iYWJpbGl0eSBIZWF0bWFwMSwgZmlnLmhlaWdodD0xMSwgZmlnLndpZHRoPTguNX0KIyBsb29rdXAgdGhlIG1pbmltdW0gQklDIHZhbHVlIGZvciBlYWNoIHNwZWNpZXMgKHdoaWNoLm1pbiB3b3JrcyBiZXR0ZXIgaGVyZSwgYmVjYXVzZSBpdCByZXR1cm5zIG9ubHkgdGhlIGZpcnN0IGluc3RhbmNlIG9mIHRoZSBtaW5pbXVtIHZhbHVlKQptaW5CSUM8LXNhcHBseShjcml0X2RmLGZ1bmN0aW9uKHgpe3hbd2hpY2gubWluKHgpXX0pIAoKI0omTyBib3ggNCBlcW4gMS4gc2NhbGUoKSBzZWVtcyB0byBiZSB0aGUgd2F5IHRvIGdvIGhlcmUsIHVzaW5nIHRoZSBtaW5CSUMgYXMgdGhlIGNlbnRlcmluZyB2ZWN0b3IKY3JpdF9kZl9kZWx0YUk8LXNjYWxlKGNyaXRfZGYsIGNlbnRlcj1taW5CSUMsIHNjYWxlPUYpIAoKI0omTyBib3ggNCBlcW4gNC4gbnVtZXJhdG9yLCBwbHVzIG1ha2UgaXQgYSBkYXRhIGZyYW1lCmNyaXRfZGZfZGVsdGFJX2I8LWFzLmRhdGEuZnJhbWUoZXhwKC0wLjUqY3JpdF9kZl9kZWx0YUkpKSAKCiNKJk8gYm94IDQgZXFuIDQuIGRlbm9taW5hdG9yCmNyaXRfZGZfZGVsdGFJX3N1bXM8LXNhcHBseShjcml0X2RmX2RlbHRhSV9iLHN1bSxuYS5ybT1UKSAKCiMgdGhpcyB0aW1lIHVzZSB0aGUgc2NhbGUgYXJndW1lbnQgb2Ygc2NhbGUgdG8gZGl2aWRlIGVhY2ggY29sdW1uIGJ5IHRoZSBjb3JyZXNwb25kaW5nIHN1bQpjcml0X2RmX3JlbGF0aXZlX3Byb2I8LXNjYWxlKGNyaXRfZGZfZGVsdGFJX2IsY2VudGVyPUYsc2NhbGU9Y3JpdF9kZl9kZWx0YUlfc3VtcykgCgoKIyMgTWFrZSBhIGhlYXRtYXAgb2YgcmVsYXRpdmUgcHJvYmFiaWxpdHkgb2YgZWFjaCBoeXBvdGhlc2lzCgojbWVsdCBmb3IgZ2dwbG90MgpyZWxwcm9iPC1tZWx0KGNyaXRfZGZfcmVsYXRpdmVfcHJvYikKY29sbmFtZXMocmVscHJvYik8LWMoIkh5cG90aGVzaXMiLCJTcGVjaWVzIiwiUmVsYXRpdmVfUHJvYmFiaWxpdHkiKQoKI2Jhc2VwbG90CnJwPC1nZ3Bsb3QocmVscHJvYixhZXMoeT1TcGVjaWVzLHg9SHlwb3RoZXNpcyxmaWxsPVJlbGF0aXZlX1Byb2JhYmlsaXR5KSkKCiNhZGQgZ2VvbV90aWxlLCB0dXJuIHRoZSB4LWF4aXMgZWxlbWVudHMgYnkgOTAgZGVncmVlcywgcmV2ZXJzZSB0aGUgbmFtZXMgb24gdGhlIHktYXhpcywgYW5kIHVzZSBhIGRpdmVyZ2luZyBjb2xvciBzY2hlbWUgdG8gaGlnaGxpZ2h0IGh5cG90aGVzZXMgd2l0aCA+NTAlIHJlbCBwcm9iLgpycDwtcnArZ2VvbV90aWxlKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkrCiAgeWxpbShyZXYobGV2ZWxzKHJlbHByb2IkU3BlY2llcykpKSsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDAuNSwgc3BhY2UgPSAicmdiIiwKICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5NTAiLCBndWlkZSA9ICJjb2xvdXJiYXIiKQpycApgYGAKCgojIyBQSElTVCBhbmQgVHJhZGl0aW9uYWwgU3BlY2llcyBCb3VuZGFyaWVzCgpDb2RlIGlzIHN1cHByZXNzZWQgZm9yIHRoZSBvdGhlciAzIGV4YW1wbGVzCgojIyMgTWVhc3VyZSBTdXBwb3J0CmBgYHtyIE1lYXN1cmUgU3VwcG9ydDIsIGVjaG89Rn0KbG9hZChmaWxlPWZpbGUucGF0aChhbW92YV90c19wYXRoLCJQSElTVF9UcmFkU3BlY190YWJsZV9hbW92YV9vdXRwdXQuUmRhdGEiKSkKCiMgTWVhc3VyZSBzdXBwb3J0IGZvciBlYWNoIGh5cG90aGVzaXMKCiNHZXQgdGhlIHZhbHVlcyBmb3IgZWFjaCBoeXBvdGhlc2lzIGZvciBhIGdpdmVuIGNyaXRlcmlvbiAtIGhlcmUgSSB1c2UgQklDIC0gYW5kIHJhbmsgdGhlbSBmb3IgI2VhY2ggc3BlY2llcywgdGhlbiBjaG9vc2UgdGhlICJiZXN0IiBoeXBvdGhlc2lzIGZvciBlYWNoIHNwZWNpZXMgYmFzZWQgb24gdGhlIGNyaXRlcmlvbi4KCmNyaXRlcmlvbjwtIkJJQyIKIyBmaW5kIHRoZSBtYXhpbXVtIG51bWJlciBvZiBzcGVjaWVzIGZyb20gYW55IG9mIHRoZSA4IGh5cG90aGVzZXMKbWF4bGVuZ3RoPC1tYXgoc2FwcGx5KGFtb3Zhc3RhdHMsZnVuY3Rpb24oeCkgbGVuZ3RoKHhbWzFdXSkpKSAKIyBjcmVhdGUgYW4gZW1wdHkgZGF0YSBmcmFtZSB3aXRoIHJvdyBuYW1lcyBmcm9tIHRoZSBoeXBvdGhlc2lzIHdpdGggdGhlIG1vc3QgdmFsdWVzCmNyaXRfZGY8LWRhdGEuZnJhbWUoc2V0TmFtZXMocmVwbGljYXRlKG1heGxlbmd0aCxudW1lcmljKDApLCBzaW1wbGlmeSA9IEYpLG5tPXJvdy5uYW1lcyhhbW92YXN0YXRzW1siUFJPVklOQ0UiXV0pKSkgCgojTG9vcCB0aHJvdWdoIHRoZSBoeXBvdGhlc2VzLCBwdWxsaW5nIG91dCB0aGUgdmFsdWVzIGZvciBjcml0ZXJpb24sdHJhbnNwb3NlIGl0LCBhbmQgdGhlbiBtZXJnZSB0aGVzZSB2YWx1ZXMgaW50byB0aGUgZGF0YWZyYW1lIGZyb20gdGhlIHByZXZpb3VzIGh5cG90aGVzaXMgCmZvcihoIGluIG5hbWVzKGFtb3Zhc3RhdHMpKXsKICBjcml0X2RmPC1tZXJnZShjcml0X2RmLHQoYW1vdmFzdGF0c1tbaF1dW2NyaXRlcmlvbl0pLGFsbD1ULHNvcnQ9RikKfQojZ2V0IHRoZSBoeXBvdGhlc2lzIG5hbWVzIGluIHRoZXJlCnJvdy5uYW1lcyhjcml0X2RmKTwtbmFtZXMoYW1vdmFzdGF0cykKCiNyYW5rIHRoZSBoeXBvdGhlc2VzIGZvciBlYWNoIHNwZWNpZXMKY3JpdF9yYW5rPC1hcy5kYXRhLmZyYW1lKHNhcHBseShjcml0X2RmLHJhbmssbmEubGFzdD0ia2VlcCIsdGllcy5tZXRob2Q9ImF2ZXJhZ2UiKSkKcm93Lm5hbWVzKGNyaXRfcmFuayk8LW5hbWVzKGFtb3Zhc3RhdHMpCgojIyByZW1vdmUgZ3NscyB3aXRoIG1vcmUgdGhhbiAzIG1pc3NpbmcgbW9kZWxzCmNyaXRfcmFuazwtY3JpdF9yYW5rWywgY29sU3Vtcyhpcy5uYShjcml0X3JhbmspKSA8IG5yb3coY3JpdF9yYW5rKS01XSAgCgojIyBjaG9vc2UgdGhlIGJlc3QgaHlwb3RoZXNpcyBvciBzZXQgb2YgaHlwb3RoZXNlcyBmb3IgZWFjaCBzcGVjaWVzICAKYmVzdF9oeXBvdGhlc2lzPC1zYXBwbHkoY3JpdF9yYW5rLGZ1bmN0aW9uKHgpe3Jvdy5uYW1lcyhjcml0X3JhbmspW3doaWNoKHg9PW1pbih4LG5hLnJtPVQpKSBdfSkKCgojIyBNYWtlIGEgYmFyIGdyYXBoIG9mIGJlc3Qgc3VwcG9ydCBmb3IgZWFjaCBoeXBvdGhlc2lzIGFtb25nIHNwZWNpZXMKCmJhcnBsb3Q8LWdncGxvdChkYXRhPWFzLmRhdGEuZnJhbWUodW5saXN0KGJlc3RfaHlwb3RoZXNpcykpLCBhZXMoeD11bmxpc3QoYmVzdF9oeXBvdGhlc2lzKSApKSArIGdlb21fYmFyKGFlcyh5ID0gKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpKSArIGxhYnMoeD0iSHlwb3RoZXNpcyIseT0iUHJvcG9ydGlvbiBvZiBTcGVjaWVzIiwgdGl0bGU9IlByb3BvcnRpb25hbCBTdXBwb3J0IGZvciBCaW9nZW9ncmFwaGljIEh5cG90aGVzZXMgYmFzZWQgb24gQklDIikKCmJhcnBsb3QKYGBgCgoKIyMjIENhbGN1bGF0ZSByZWxhdGl2ZSBwcm9iYWJpbGl0eSBmcm9tIEpvaG5zb24gYW5kIE9tbGFuZCAyMDA0IGFuZCB2aXN1YWxpemUgd2l0aCBhIGhlYXRtYXAKYGBge3IgUmVsYXRpdmUgUHJvYmFiaWxpdHkgSGVhdG1hcDIsIGVjaG89Rn0KIyBsb29rdXAgdGhlIG1pbmltdW0gQklDIHZhbHVlIGZvciBlYWNoIHNwZWNpZXMgKHdoaWNoLm1pbiB3b3JrcyBiZXR0ZXIgaGVyZSwgYmVjYXVzZSBpdCByZXR1cm5zIG9ubHkgdGhlIGZpcnN0IGluc3RhbmNlIG9mIHRoZSBtaW5pbXVtIHZhbHVlKQptaW5CSUM8LXNhcHBseShjcml0X2RmLGZ1bmN0aW9uKHgpe3hbd2hpY2gubWluKHgpXX0pIAoKI0omTyBib3ggNCBlcW4gMS4gc2NhbGUoKSBzZWVtcyB0byBiZSB0aGUgd2F5IHRvIGdvIGhlcmUsIHVzaW5nIHRoZSBtaW5CSUMgYXMgdGhlIGNlbnRlcmluZyB2ZWN0b3IKY3JpdF9kZl9kZWx0YUk8LXNjYWxlKGNyaXRfZGYsIGNlbnRlcj1taW5CSUMsIHNjYWxlPUYpIAoKI0omTyBib3ggNCBlcW4gNC4gbnVtZXJhdG9yLCBwbHVzIG1ha2UgaXQgYSBkYXRhIGZyYW1lCmNyaXRfZGZfZGVsdGFJX2I8LWFzLmRhdGEuZnJhbWUoZXhwKC0wLjUqY3JpdF9kZl9kZWx0YUkpKSAKCiNKJk8gYm94IDQgZXFuIDQuIGRlbm9taW5hdG9yCmNyaXRfZGZfZGVsdGFJX3N1bXM8LXNhcHBseShjcml0X2RmX2RlbHRhSV9iLHN1bSxuYS5ybT1UKSAKCiMgdGhpcyB0aW1lIHVzZSB0aGUgc2NhbGUgYXJndW1lbnQgb2Ygc2NhbGUgdG8gZGl2aWRlIGVhY2ggY29sdW1uIGJ5IHRoZSBjb3JyZXNwb25kaW5nIHN1bQpjcml0X2RmX3JlbGF0aXZlX3Byb2I8LXNjYWxlKGNyaXRfZGZfZGVsdGFJX2IsY2VudGVyPUYsc2NhbGU9Y3JpdF9kZl9kZWx0YUlfc3VtcykgCgoKIyMgTWFrZSBhIGhlYXRtYXAgb2YgcmVsYXRpdmUgcHJvYmFiaWxpdHkgb2YgZWFjaCBoeXBvdGhlc2lzCgojbWVsdCBmb3IgZ2dwbG90MgpyZWxwcm9iPC1tZWx0KGNyaXRfZGZfcmVsYXRpdmVfcHJvYikKY29sbmFtZXMocmVscHJvYik8LWMoIkh5cG90aGVzaXMiLCJTcGVjaWVzIiwiUmVsYXRpdmVfUHJvYmFiaWxpdHkiKQoKI2Jhc2VwbG90CnJwPC1nZ3Bsb3QocmVscHJvYixhZXMoeT1TcGVjaWVzLHg9SHlwb3RoZXNpcyxmaWxsPVJlbGF0aXZlX1Byb2JhYmlsaXR5KSkKCiNhZGQgZ2VvbV90aWxlLCB0dXJuIHRoZSB4LWF4aXMgZWxlbWVudHMgYnkgOTAgZGVncmVlcywgcmV2ZXJzZSB0aGUgbmFtZXMgb24gdGhlIHktYXhpcywgYW5kIHVzZSBhIGRpdmVyZ2luZyBjb2xvciBzY2hlbWUgdG8gaGlnaGxpZ2h0IGh5cG90aGVzZXMgd2l0aCA+NTAlIHJlbCBwcm9iLgpycDwtcnArZ2VvbV90aWxlKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkrCiAgeWxpbShyZXYobGV2ZWxzKHJlbHByb2IkU3BlY2llcykpKSsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDAuNSwgc3BhY2UgPSAicmdiIiwKICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5NTAiLCBndWlkZSA9ICJjb2xvdXJiYXIiKQpycApgYGAKIyMgRlNUIGFuZCBBQkdEIEJvdW5kYXJpZXMKCiMjIyBNZWFzdXJlIFN1cHBvcnQKYGBge3IgTWVhc3VyZSBTdXBwb3J0MywgZWNobz1GfQpsb2FkKGZpbGU9ZmlsZS5wYXRoKGFtb3ZhX2FiZ2RfcGF0aCwiRlNUX0FCR0RfdGFibGVfYW1vdmFfb3V0cHV0LlJkYXRhIikpCgojIE1lYXN1cmUgc3VwcG9ydCBmb3IgZWFjaCBoeXBvdGhlc2lzCgojR2V0IHRoZSB2YWx1ZXMgZm9yIGVhY2ggaHlwb3RoZXNpcyBmb3IgYSBnaXZlbiBjcml0ZXJpb24gLSBoZXJlIEkgdXNlIEJJQyAtIGFuZCByYW5rIHRoZW0gZm9yICNlYWNoIHNwZWNpZXMsIHRoZW4gY2hvb3NlIHRoZSAiYmVzdCIgaHlwb3RoZXNpcyBmb3IgZWFjaCBzcGVjaWVzIGJhc2VkIG9uIHRoZSBjcml0ZXJpb24uCgpjcml0ZXJpb248LSJCSUMiCiMgZmluZCB0aGUgbWF4aW11bSBudW1iZXIgb2Ygc3BlY2llcyBmcm9tIGFueSBvZiB0aGUgOCBoeXBvdGhlc2VzCm1heGxlbmd0aDwtbWF4KHNhcHBseShhbW92YXN0YXRzLGZ1bmN0aW9uKHgpIGxlbmd0aCh4W1sxXV0pKSkgCiMgY3JlYXRlIGFuIGVtcHR5IGRhdGEgZnJhbWUgd2l0aCByb3cgbmFtZXMgZnJvbSB0aGUgaHlwb3RoZXNpcyB3aXRoIHRoZSBtb3N0IHZhbHVlcwpjcml0X2RmPC1kYXRhLmZyYW1lKHNldE5hbWVzKHJlcGxpY2F0ZShtYXhsZW5ndGgsbnVtZXJpYygwKSwgc2ltcGxpZnkgPSBGKSxubT1yb3cubmFtZXMoYW1vdmFzdGF0c1tbIlBST1ZJTkNFIl1dKSkpIAoKI0xvb3AgdGhyb3VnaCB0aGUgaHlwb3RoZXNlcywgcHVsbGluZyBvdXQgdGhlIHZhbHVlcyBmb3IgY3JpdGVyaW9uLHRyYW5zcG9zZSBpdCwgYW5kIHRoZW4gbWVyZ2UgdGhlc2UgdmFsdWVzIGludG8gdGhlIGRhdGFmcmFtZSBmcm9tIHRoZSBwcmV2aW91cyBoeXBvdGhlc2lzIApmb3IoaCBpbiBuYW1lcyhhbW92YXN0YXRzKSl7CiAgY3JpdF9kZjwtbWVyZ2UoY3JpdF9kZix0KGFtb3Zhc3RhdHNbW2hdXVtjcml0ZXJpb25dKSxhbGw9VCxzb3J0PUYpCn0KI2dldCB0aGUgaHlwb3RoZXNpcyBuYW1lcyBpbiB0aGVyZQpyb3cubmFtZXMoY3JpdF9kZik8LW5hbWVzKGFtb3Zhc3RhdHMpCgojcmFuayB0aGUgaHlwb3RoZXNlcyBmb3IgZWFjaCBzcGVjaWVzCmNyaXRfcmFuazwtYXMuZGF0YS5mcmFtZShzYXBwbHkoY3JpdF9kZixyYW5rLG5hLmxhc3Q9ImtlZXAiLHRpZXMubWV0aG9kPSJhdmVyYWdlIikpCnJvdy5uYW1lcyhjcml0X3JhbmspPC1uYW1lcyhhbW92YXN0YXRzKQoKIyMgcmVtb3ZlIGdzbHMgd2l0aCBtb3JlIHRoYW4gMyBtaXNzaW5nIG1vZGVscwpjcml0X3Jhbms8LWNyaXRfcmFua1ssIGNvbFN1bXMoaXMubmEoY3JpdF9yYW5rKSkgPCBucm93KGNyaXRfcmFuayktNV0gIAoKIyMgY2hvb3NlIHRoZSBiZXN0IGh5cG90aGVzaXMgb3Igc2V0IG9mIGh5cG90aGVzZXMgZm9yIGVhY2ggc3BlY2llcyAgCmJlc3RfaHlwb3RoZXNpczwtc2FwcGx5KGNyaXRfcmFuayxmdW5jdGlvbih4KXtyb3cubmFtZXMoY3JpdF9yYW5rKVt3aGljaCh4PT1taW4oeCxuYS5ybT1UKSkgXX0pCgoKIyMgTWFrZSBhIGJhciBncmFwaCBvZiBiZXN0IHN1cHBvcnQgZm9yIGVhY2ggaHlwb3RoZXNpcyBhbW9uZyBzcGVjaWVzCgpiYXJwbG90PC1nZ3Bsb3QoZGF0YT1hcy5kYXRhLmZyYW1lKHVubGlzdChiZXN0X2h5cG90aGVzaXMpKSwgYWVzKHg9dW5saXN0KGJlc3RfaHlwb3RoZXNpcykgKSkgKyBnZW9tX2JhcihhZXMoeSA9ICguLmNvdW50Li4pL3N1bSguLmNvdW50Li4pKSkgKyBsYWJzKHg9Ikh5cG90aGVzaXMiLHk9IlByb3BvcnRpb24gb2YgU3BlY2llcyIsIHRpdGxlPSJQcm9wb3J0aW9uYWwgU3VwcG9ydCBmb3IgQmlvZ2VvZ3JhcGhpYyBIeXBvdGhlc2VzIGJhc2VkIG9uIEJJQyIpCgpiYXJwbG90CmBgYAoKCiMjIyBDYWxjdWxhdGUgcmVsYXRpdmUgcHJvYmFiaWxpdHkgZnJvbSBKb2huc29uIGFuZCBPbWxhbmQgMjAwNCBhbmQgdmlzdWFsaXplIHdpdGggYSBoZWF0bWFwCmBgYHtyIFJlbGF0aXZlIFByb2JhYmlsaXR5IEhlYXRtYXAzLCBlY2hvPUZ9CiMgbG9va3VwIHRoZSBtaW5pbXVtIEJJQyB2YWx1ZSBmb3IgZWFjaCBzcGVjaWVzICh3aGljaC5taW4gd29ya3MgYmV0dGVyIGhlcmUsIGJlY2F1c2UgaXQgcmV0dXJucyBvbmx5IHRoZSBmaXJzdCBpbnN0YW5jZSBvZiB0aGUgbWluaW11bSB2YWx1ZSkKbWluQklDPC1zYXBwbHkoY3JpdF9kZixmdW5jdGlvbih4KXt4W3doaWNoLm1pbih4KV19KSAKCiNKJk8gYm94IDQgZXFuIDEuIHNjYWxlKCkgc2VlbXMgdG8gYmUgdGhlIHdheSB0byBnbyBoZXJlLCB1c2luZyB0aGUgbWluQklDIGFzIHRoZSBjZW50ZXJpbmcgdmVjdG9yCmNyaXRfZGZfZGVsdGFJPC1zY2FsZShjcml0X2RmLCBjZW50ZXI9bWluQklDLCBzY2FsZT1GKSAKCiNKJk8gYm94IDQgZXFuIDQuIG51bWVyYXRvciwgcGx1cyBtYWtlIGl0IGEgZGF0YSBmcmFtZQpjcml0X2RmX2RlbHRhSV9iPC1hcy5kYXRhLmZyYW1lKGV4cCgtMC41KmNyaXRfZGZfZGVsdGFJKSkgCgojSiZPIGJveCA0IGVxbiA0LiBkZW5vbWluYXRvcgpjcml0X2RmX2RlbHRhSV9zdW1zPC1zYXBwbHkoY3JpdF9kZl9kZWx0YUlfYixzdW0sbmEucm09VCkgCgojIHRoaXMgdGltZSB1c2UgdGhlIHNjYWxlIGFyZ3VtZW50IG9mIHNjYWxlIHRvIGRpdmlkZSBlYWNoIGNvbHVtbiBieSB0aGUgY29ycmVzcG9uZGluZyBzdW0KY3JpdF9kZl9yZWxhdGl2ZV9wcm9iPC1zY2FsZShjcml0X2RmX2RlbHRhSV9iLGNlbnRlcj1GLHNjYWxlPWNyaXRfZGZfZGVsdGFJX3N1bXMpIAoKCiMjIE1ha2UgYSBoZWF0bWFwIG9mIHJlbGF0aXZlIHByb2JhYmlsaXR5IG9mIGVhY2ggaHlwb3RoZXNpcwoKI21lbHQgZm9yIGdncGxvdDIKcmVscHJvYjwtbWVsdChjcml0X2RmX3JlbGF0aXZlX3Byb2IpCmNvbG5hbWVzKHJlbHByb2IpPC1jKCJIeXBvdGhlc2lzIiwiU3BlY2llcyIsIlJlbGF0aXZlX1Byb2JhYmlsaXR5IikKCiNiYXNlcGxvdApycDwtZ2dwbG90KHJlbHByb2IsYWVzKHk9U3BlY2llcyx4PUh5cG90aGVzaXMsZmlsbD1SZWxhdGl2ZV9Qcm9iYWJpbGl0eSkpCgojYWRkIGdlb21fdGlsZSwgdHVybiB0aGUgeC1heGlzIGVsZW1lbnRzIGJ5IDkwIGRlZ3JlZXMsIHJldmVyc2UgdGhlIG5hbWVzIG9uIHRoZSB5LWF4aXMsIGFuZCB1c2UgYSBkaXZlcmdpbmcgY29sb3Igc2NoZW1lIHRvIGhpZ2hsaWdodCBoeXBvdGhlc2VzIHdpdGggPjUwJSByZWwgcHJvYi4KcnA8LXJwK2dlb21fdGlsZSgpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpKwogIHlsaW0ocmV2KGxldmVscyhyZWxwcm9iJFNwZWNpZXMpKSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBtaWQgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAwLjUsIHNwYWNlID0gInJnYiIsCiAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiZ3JleTUwIiwgZ3VpZGUgPSAiY29sb3VyYmFyIikKcnAKYGBgCgojIyBQSElTVCBhbmQgQUJHRCBCb3VuZGFyaWVzCgojIyMgTWVhc3VyZSBTdXBwb3J0CmBgYHtyIE1lYXN1cmUgU3VwcG9ydDQsIGVjaG89Rn0KbG9hZChmaWxlPWZpbGUucGF0aChhbW92YV9hYmdkX3BhdGgsIlBISVNUX0FCR0RfdGFibGVfYW1vdmFfb3V0cHV0LlJkYXRhIikpCgojIE1lYXN1cmUgc3VwcG9ydCBmb3IgZWFjaCBoeXBvdGhlc2lzCgojR2V0IHRoZSB2YWx1ZXMgZm9yIGVhY2ggaHlwb3RoZXNpcyBmb3IgYSBnaXZlbiBjcml0ZXJpb24gLSBoZXJlIEkgdXNlIEJJQyAtIGFuZCByYW5rIHRoZW0gZm9yICNlYWNoIHNwZWNpZXMsIHRoZW4gY2hvb3NlIHRoZSAiYmVzdCIgaHlwb3RoZXNpcyBmb3IgZWFjaCBzcGVjaWVzIGJhc2VkIG9uIHRoZSBjcml0ZXJpb24uCgpjcml0ZXJpb248LSJCSUMiCiMgZmluZCB0aGUgbWF4aW11bSBudW1iZXIgb2Ygc3BlY2llcyBmcm9tIGFueSBvZiB0aGUgOCBoeXBvdGhlc2VzCm1heGxlbmd0aDwtbWF4KHNhcHBseShhbW92YXN0YXRzLGZ1bmN0aW9uKHgpIGxlbmd0aCh4W1sxXV0pKSkgCiMgY3JlYXRlIGFuIGVtcHR5IGRhdGEgZnJhbWUgd2l0aCByb3cgbmFtZXMgZnJvbSB0aGUgaHlwb3RoZXNpcyB3aXRoIHRoZSBtb3N0IHZhbHVlcwpjcml0X2RmPC1kYXRhLmZyYW1lKHNldE5hbWVzKHJlcGxpY2F0ZShtYXhsZW5ndGgsbnVtZXJpYygwKSwgc2ltcGxpZnkgPSBGKSxubT1yb3cubmFtZXMoYW1vdmFzdGF0c1tbIlBST1ZJTkNFIl1dKSkpIAoKI0xvb3AgdGhyb3VnaCB0aGUgaHlwb3RoZXNlcywgcHVsbGluZyBvdXQgdGhlIHZhbHVlcyBmb3IgY3JpdGVyaW9uLHRyYW5zcG9zZSBpdCwgYW5kIHRoZW4gbWVyZ2UgdGhlc2UgdmFsdWVzIGludG8gdGhlIGRhdGFmcmFtZSBmcm9tIHRoZSBwcmV2aW91cyBoeXBvdGhlc2lzIApmb3IoaCBpbiBuYW1lcyhhbW92YXN0YXRzKSl7CiAgY3JpdF9kZjwtbWVyZ2UoY3JpdF9kZix0KGFtb3Zhc3RhdHNbW2hdXVtjcml0ZXJpb25dKSxhbGw9VCxzb3J0PUYpCn0KI2dldCB0aGUgaHlwb3RoZXNpcyBuYW1lcyBpbiB0aGVyZQpyb3cubmFtZXMoY3JpdF9kZik8LW5hbWVzKGFtb3Zhc3RhdHMpCgojcmFuayB0aGUgaHlwb3RoZXNlcyBmb3IgZWFjaCBzcGVjaWVzCmNyaXRfcmFuazwtYXMuZGF0YS5mcmFtZShzYXBwbHkoY3JpdF9kZixyYW5rLG5hLmxhc3Q9ImtlZXAiLHRpZXMubWV0aG9kPSJhdmVyYWdlIikpCnJvdy5uYW1lcyhjcml0X3JhbmspPC1uYW1lcyhhbW92YXN0YXRzKQoKIyMgcmVtb3ZlIGdzbHMgd2l0aCBtb3JlIHRoYW4gMyBtaXNzaW5nIG1vZGVscwpjcml0X3Jhbms8LWNyaXRfcmFua1ssIGNvbFN1bXMoaXMubmEoY3JpdF9yYW5rKSkgPCBucm93KGNyaXRfcmFuayktNV0gIAoKIyMgY2hvb3NlIHRoZSBiZXN0IGh5cG90aGVzaXMgb3Igc2V0IG9mIGh5cG90aGVzZXMgZm9yIGVhY2ggc3BlY2llcyAgCmJlc3RfaHlwb3RoZXNpczwtc2FwcGx5KGNyaXRfcmFuayxmdW5jdGlvbih4KXtyb3cubmFtZXMoY3JpdF9yYW5rKVt3aGljaCh4PT1taW4oeCxuYS5ybT1UKSkgXX0pCgoKIyMgTWFrZSBhIGJhciBncmFwaCBvZiBiZXN0IHN1cHBvcnQgZm9yIGVhY2ggaHlwb3RoZXNpcyBhbW9uZyBzcGVjaWVzCgpiYXJwbG90PC1nZ3Bsb3QoZGF0YT1hcy5kYXRhLmZyYW1lKHVubGlzdChiZXN0X2h5cG90aGVzaXMpKSwgYWVzKHg9dW5saXN0KGJlc3RfaHlwb3RoZXNpcykgKSkgKyBnZW9tX2JhcihhZXMoeSA9ICguLmNvdW50Li4pL3N1bSguLmNvdW50Li4pKSkgKyBsYWJzKHg9Ikh5cG90aGVzaXMiLHk9IlByb3BvcnRpb24gb2YgU3BlY2llcyIsIHRpdGxlPSJQcm9wb3J0aW9uYWwgU3VwcG9ydCBmb3IgQmlvZ2VvZ3JhcGhpYyBIeXBvdGhlc2VzIGJhc2VkIG9uIEJJQyIpCgpiYXJwbG90CmBgYAoKCiMjIyBDYWxjdWxhdGUgcmVsYXRpdmUgcHJvYmFiaWxpdHkgZnJvbSBKb2huc29uIGFuZCBPbWxhbmQgMjAwNCBhbmQgdmlzdWFsaXplIHdpdGggYSBoZWF0bWFwCmBgYHtyIFJlbGF0aXZlIFByb2JhYmlsaXR5IEhlYXRtYXA0LCBlY2hvPUZ9CiMgbG9va3VwIHRoZSBtaW5pbXVtIEJJQyB2YWx1ZSBmb3IgZWFjaCBzcGVjaWVzICh3aGljaC5taW4gd29ya3MgYmV0dGVyIGhlcmUsIGJlY2F1c2UgaXQgcmV0dXJucyBvbmx5IHRoZSBmaXJzdCBpbnN0YW5jZSBvZiB0aGUgbWluaW11bSB2YWx1ZSkKbWluQklDPC1zYXBwbHkoY3JpdF9kZixmdW5jdGlvbih4KXt4W3doaWNoLm1pbih4KV19KSAKCiNKJk8gYm94IDQgZXFuIDEuIHNjYWxlKCkgc2VlbXMgdG8gYmUgdGhlIHdheSB0byBnbyBoZXJlLCB1c2luZyB0aGUgbWluQklDIGFzIHRoZSBjZW50ZXJpbmcgdmVjdG9yCmNyaXRfZGZfZGVsdGFJPC1zY2FsZShjcml0X2RmLCBjZW50ZXI9bWluQklDLCBzY2FsZT1GKSAKCiNKJk8gYm94IDQgZXFuIDQuIG51bWVyYXRvciwgcGx1cyBtYWtlIGl0IGEgZGF0YSBmcmFtZQpjcml0X2RmX2RlbHRhSV9iPC1hcy5kYXRhLmZyYW1lKGV4cCgtMC41KmNyaXRfZGZfZGVsdGFJKSkgCgojSiZPIGJveCA0IGVxbiA0LiBkZW5vbWluYXRvcgpjcml0X2RmX2RlbHRhSV9zdW1zPC1zYXBwbHkoY3JpdF9kZl9kZWx0YUlfYixzdW0sbmEucm09VCkgCgojIHRoaXMgdGltZSB1c2UgdGhlIHNjYWxlIGFyZ3VtZW50IG9mIHNjYWxlIHRvIGRpdmlkZSBlYWNoIGNvbHVtbiBieSB0aGUgY29ycmVzcG9uZGluZyBzdW0KY3JpdF9kZl9yZWxhdGl2ZV9wcm9iPC1zY2FsZShjcml0X2RmX2RlbHRhSV9iLGNlbnRlcj1GLHNjYWxlPWNyaXRfZGZfZGVsdGFJX3N1bXMpIAoKCiMjIE1ha2UgYSBoZWF0bWFwIG9mIHJlbGF0aXZlIHByb2JhYmlsaXR5IG9mIGVhY2ggaHlwb3RoZXNpcwoKI21lbHQgZm9yIGdncGxvdDIKcmVscHJvYjwtbWVsdChjcml0X2RmX3JlbGF0aXZlX3Byb2IpCmNvbG5hbWVzKHJlbHByb2IpPC1jKCJIeXBvdGhlc2lzIiwiU3BlY2llcyIsIlJlbGF0aXZlX1Byb2JhYmlsaXR5IikKCiNiYXNlcGxvdApycDwtZ2dwbG90KHJlbHByb2IsYWVzKHk9U3BlY2llcyx4PUh5cG90aGVzaXMsZmlsbD1SZWxhdGl2ZV9Qcm9iYWJpbGl0eSkpCgojYWRkIGdlb21fdGlsZSwgdHVybiB0aGUgeC1heGlzIGVsZW1lbnRzIGJ5IDkwIGRlZ3JlZXMsIHJldmVyc2UgdGhlIG5hbWVzIG9uIHRoZSB5LWF4aXMsIGFuZCB1c2UgYSBkaXZlcmdpbmcgY29sb3Igc2NoZW1lIHRvIGhpZ2hsaWdodCBoeXBvdGhlc2VzIHdpdGggPjUwJSByZWwgcHJvYi4KcnA8LXJwK2dlb21fdGlsZSgpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpKwogIHlsaW0ocmV2KGxldmVscyhyZWxwcm9iJFNwZWNpZXMpKSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBtaWQgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAwLjUsIHNwYWNlID0gInJnYiIsCiAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiZ3JleTUwIiwgZ3VpZGUgPSAiY29sb3VyYmFyIikKcnAKYGBgCgojIENhbGN1bGF0ZSBQYWlyd2lzZSBEaWZmZXJlbnRpYXRpb24gU3RhdHMKCkJ5IHNhbXBsZQoKYGBge3IsIGV2YWw9Rn0KZGlmZnN0YXRzPC1wYWlyd2lzZS5zdHJ1Y3R1cmUubXRETkEuZGIoaXBkYj1pcGRiLCBnZGlzdCA9ICJXQyBUaGV0YSIsIG1pbnNlcXMgPSA1LCBtaW5zYW1wcyA9IDMsIG1pbnRvdGFsc2VxcyA9IDAsIG5yZXAgPSAwLCBudW0uY29yZXMgPSAyLCBBQkdEID0gVCwgcmVnaW9uYWxpemF0aW9uID0gInNhbXBsZSIpCgoKc2F2ZShkaWZmc3RhdHMsIGZpbGU9Ii9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X0VTVS9QYWlyd2lzZV9zdGF0aXN0aWNzL0RJUG5ldF9zdHJ1Y3R1cmVfc2FtcGxlX1dDVGhldGFfQUJHRC5SZGF0YSIpCgpkaWZmc3RhdHM8LXBhaXJ3aXNlLnN0cnVjdHVyZS5tdEROQS5kYihpcGRiPWlwZGIsIGdkaXN0ID0gIkpvc3QgRCIsIG1pbnNlcXMgPSA1LCBtaW5zYW1wcyA9IDMsIG1pbnRvdGFsc2VxcyA9IDAsIG5yZXAgPSAwLCBudW0uY29yZXMgPSAyLCBBQkdEID0gVCwgcmVnaW9uYWxpemF0aW9uID0gInNhbXBsZSIpCgoKc2F2ZShkaWZmc3RhdHMsIGZpbGU9Ii9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X0VTVS9QYWlyd2lzZV9zdGF0aXN0aWNzL0RJUG5ldF9zdHJ1Y3R1cmVfc2FtcGxlX0pvc3REX0FCR0QuUmRhdGEiKQpgYGAKCiMgR2VuZXJhbGl6ZWQgRGlzc2ltaWxhcml0eSBNb2RlbGluZwoKIyMgVHJhZGl0aW9uYWwgU3BlY2llcyBCb3VuZGFyaWVzCmBgYHtyIEdETTEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgogIGxvYWQoIi9Vc2Vycy9lcmljL2dvb2dsZV9kcml2ZS9ESVBuZXRfR2FpdF9MaWdfQmlyZC9ESVBuZXRfV0c0X2ZpcnN0X3BhcGVycy9zdGF0aXN0aWNzL0J5X1NwZWNpZXMvUGFpcndpc2Vfc3RhdGlzdGljcy9zYW1wbGUvRElQbmV0X3N0cnVjdHVyZV9zYW1wbGVfUGhpU1QuUmRhdGEiKQoKZXN1X2xvY2kgPC0gdW5pcXVlKGlwZGIkR2VudXNfc3BlY2llc19sb2N1cykKCmdkbS5mdWxsPC1saXN0KCkKCnNvbHV0aW9uPC1saXN0KCkKbm9zb2x1dGlvbjwtbGlzdCgpCm5vc29sdXRpb24uZnVsbDwtbGlzdCgpCm5vc29sdXRpb24ubGlzdDwtbGlzdCgpCgpzdGF0cy5mdWxsPC1kYXRhLmZyYW1lKFNwZWNpZXNfTG9jdXM9Y2hhcmFjdGVyKDApLFdpdGhSZWdpb25zRGV2aWFuY2U9bnVtZXJpYygwKSxXaXRoUmVnaW9uc0V4cGxhaW5lZERldmlhbmNlPW51bWVyaWMoMCksTm9SZWdpb25zRGV2aWFuY2U9bnVtZXJpYygwKSxOb1JlZ2lvbnNFeHBsYWluZWREZXZpYW5jZT1udW1lcmljKDApLERlbHRhRGV2aWFuY2U9bnVtZXJpYygwKSxQdmFsdWVfcmVnaW9ucz1udW1lcmljKDApLFB2YWx1ZV9kaXN0PW51bWVyaWMoMCksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgpzdGF0czwtZGF0YS5mcmFtZShTcGVjaWVzX0xvY3VzPWNoYXJhY3RlcigwKSxCYXJyaWVyPWNoYXJhY3RlcigwKSxXaXRoQmFycmllckRldmlhbmNlPW51bWVyaWMoMCksV2l0aEJhcnJpZXJFeHBsYWluZWREZXZpYW5jZT1udW1lcmljKDApLEltcG9ydGFuY2VEaXN0YW5jZVdpdGhCYXJyaWVyPW51bWVyaWMoMCksSW1wb3J0YW5jZUJhcnJpZXJXaXRoQmFycmllcj1udW1lcmljKDApLE5vQmFycmllckRldmlhbmNlPW51bWVyaWMoMCksTm9CYXJyaWVyRXhwbGFpbmVkRGV2aWFuY2U9bnVtZXJpYygwKSxJbXBvcnRhbmNlRGlzdGFuY2VXaXRob3V0QmFycmllcj1udW1lcmljKDApLERlbHRhRGV2aWFuY2U9bnVtZXJpYygwKSxQdmFsdWVfYmFycmllcj1udW1lcmljKDApLFB2YWx1ZV9kaXN0PW51bWVyaWMoMCksTVJETS5yc3F1YXJlZD1udW1lcmljKDApLE1SRE0ucnNxdWFyZWQucHZhbHVlPW51bWVyaWMoMCksTVJETS5kaXN0LnB2YWx1ZT1udW1lcmljKDApLCBNUkRNLmJhcnJpZXIucHZhbHVlPW51bWVyaWMoMCksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgpub3N0YXRzPC1OVUxMCgpiYXJyaWVydGVzdHM8LWRhdGEuZnJhbWUoU3BlY2llcz1jaGFyYWN0ZXIoMCksUmVnaW9uMT1jaGFyYWN0ZXIoMCksTnVtUG9wczE9bnVtZXJpYygwKSxSZWdpb24yPWNoYXJhY3RlcigwKSxOdW1wb3BzMj1udW1lcmljKDApLCBUZXN0PWxvZ2ljYWwoMCksIFNvbHV0aW9uPWxvZ2ljYWwoMCksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgprPC0wCgpmb3IoZ3NsIGluIGVzdV9sb2NpKXsgI2dzbDwtIkxpbmNraWFfbGFldmlnYXRhX0NPMSIgIlRyaWRhY25hX2Nyb2NlYV9DTzEiICJMdXRqYW51c19rYXNtaXJhX0NZQiIgIkFjYW50aGFzdGVyX3BsYW5jaV9DTzEiCiAgCiAgY2F0KCJcbiIsIlxuIiwiXG4iLCJOb3cgc3RhcnRpbmciLCBnc2wsICJcbiIpCiAgCiAgaWYoYW55KGlzLm5hKGRpZmZzdGF0c1tbZ3NsXV0pKSl7Y2F0KCJOQXMgaW4gRlNUIHRhYmxlLCBObyBnZG0gY2FsY3VsYXRlZCIpOyBuZXh0fQogIAogIGlmKGRpZmZzdGF0c1tbZ3NsXV09PSJGZXdlciB0aGFuIDMgc2FtcGxlZCBwb3B1bGF0aW9ucyBhZnRlciBmaWx0ZXJpbmcuIE5vIHN0YXRzIGNhbGN1bGF0ZWQiKXtub3N0YXRzPC1jKG5vc3RhdHMsZ3NsKTtuZXh0fQogIAogICNwdWxsIG91dCB0aGUgZGF0YSBmb3IgdGhpcyBnZW51cy1zcGVjaWVzLWxvY3VzIChnc2wpCiAgc3A8LWlwZGJbd2hpY2goaXBkYiRHZW51c19zcGVjaWVzX2xvY3VzPT1nc2wpLF0KICAjY2xlYW4gd2VpcmQgYmFja3NsYXNoZXMgZnJvbSBuYW1lcwogIHNwJGxvY2FsaXR5PC1nc3ViKCJcIiIsIiIsc3AkbG9jYWxpdHkpCiAgCiAgc3Akc2FtcGxlPC1wYXN0ZShzcCRsb2NhbGl0eSxyb3VuZChzcCRkZWNpbWFsTGF0aXR1ZGUsIGRpZ2l0cz0wKSxyb3VuZChzcCRkZWNpbWFsTG9uZ2l0dWRlLCBkaWdpdHM9MCksc2VwPSJfIikgICNzZXRzIHVwIGEgdmFyaWFibGUgdGhhdCBtYXRjaGVzIHRoZSBuYW1lIGluIEZzdCB0YWJsZQogIHNwPC1zcFtvcmRlcihzcCRzYW1wbGUpLF0KICAjIE5vdCBhbGwgbG9jYWxpdGllcyBhcmUgaW5jbHVkZWQgaW4gVmVyb24ncyByZWdpb25hbGl6YXRpb24gKGUuZy4gR3VhbSksIHNvIGdldCB0aGVpciBuYW1lcyBhbmQgdGhlbiB6YXAgTkFzCiAgbm9uVmVyb25wb3BzPC11bmlxdWUoc3Akc2FtcGxlW2lzLm5hKHNwJFZlcm9uRGl2aXMpXSkKICBzcDwtc3BbIWlzLm5hKHNwJFZlcm9uRGl2aXMpLF0KICAKICAjc3Vic2FtcGxlIEZzdCAKICBnc2xGU1Q8LWRpZmZzdGF0c1tbZ3NsXV0KICAjbWFrZSBhIG1hdHJpeCBvdXQgb2YgZ3NsRlNUCiAgZ3NsRlNUbTwtYXMubWF0cml4KGdzbEZTVCkKICAKICBnc2xGU1RtW3doaWNoKGdzbEZTVG0gPiAxKV0gPC0gMSAjc29tZSB2YWx1ZXMgdGhhdCBsb29rIGxpa2UgMS4wMDAwIGFyZSByZWdpc3RlcmluZyBhcyBncmVhdGVyIHRoYW4gMQogIGdzbEZTVG1bd2hpY2goZ3NsRlNUbSA8IDApXSA8LSAwLjAwMDEgI2dldCByaWQgb2YgYXJ0aWZhY3R1YWwgbmVnYXRpdmUgdmFsdWVzCiAgI2dzbEZTVG08LXJlc2NhbGUoZ3NsRlNUbSkKICAjZ3NsRlNUbTwtZ3NsRlNUbS8oMS1nc2xGU1RtKQogIAogICN6YXAgd2VpcmQgc2xhc2hlcyBpbiB0aGUgbmFtZXMKICByb3duYW1lcyhnc2xGU1RtKTwtZ3N1YigiXCIiLCIiLHJvd25hbWVzKGdzbEZTVG0pKQogIGNvbG5hbWVzKGdzbEZTVG0pPC1yb3duYW1lcyhnc2xGU1RtKQogIAogICN6YXAgdGhlIHNhbWUgbmEgcG9wdWxhdGlvbnMgZnJvbSB0aGUgbGlzdCBvZiBub24gZXhpc3RlbnQgcG9wcyBmcm9tIFZlcm9uRGl2aXMKICBpZihhbnkocm93bmFtZXMoZ3NsRlNUbSkgJWluJSBub25WZXJvbnBvcHMpKXsKICAgIGdzbEZTVG08LWdzbEZTVG1bLSh3aGljaChyb3duYW1lcyhnc2xGU1RtKSAlaW4lIG5vblZlcm9ucG9wcykpLC0od2hpY2goY29sbmFtZXMoZ3NsRlNUbSkgJWluJSBub25WZXJvbnBvcHMpKV0KICB9CiAgCiAgaWYobGVuZ3RoKHJvd25hbWVzKGdzbEZTVG0pKTw1KXtub3N0YXRzPC1jKG5vc3RhdHMsZ3NsKTtjYXQoIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIik7bmV4dH0KICAKICAjYW5kIGZpbHRlciBzcCBiYXNlZCBvbiB0aGUgbG9jYWxpdGllcyB0aGF0IGhhdmUgRnN0IHZhbHVlcwogIHNwPC1zcFtzcCRzYW1wbGUgJWluJSByb3duYW1lcyhnc2xGU1RtKSxdCiAgCiAgI2FuZCB2aWNlIHZlcnNhCiAgCiAgZ3NsRlNUbTwtIGdzbEZTVG1bd2hpY2gocm93bmFtZXMoZ3NsRlNUbSkgJWluJSB1bmlxdWUoc3Akc2FtcGxlKSksd2hpY2gocm93bmFtZXMoZ3NsRlNUbSkgJWluJSB1bmlxdWUoc3Akc2FtcGxlKSldCiAgCgoKICAjY3JlYXRlIGEgbG9jYXRpb25zIGRhdGEgZnJhbWUgdGhhdCBoYXMgYWxsIHRoZSBsb2NhbGl0aWVzIHBsdXMgbGF0cyBhbmQgbG9uZ3MgYW5kIHRoZWlyIFZlcm9uIHJlZ2lvbi4KICBsb2NzPC1hcy5kYXRhLmZyYW1lKHVuaXF1ZShzcCRzYW1wbGUpKQogIG5hbWVzKGxvY3MpPC0ic2FtcGxlIgogICNsb2NzJExvbmc8LXNwJGRlY2ltYWxMb25naXR1ZGVbd2hpY2gobG9jcyAlaW4lIHNwJHNhbXBsZSldCiAgI2Nhbid0IGRvIGEgdW5pcXVlIG9uIHNhbXBsZSwgbGF0cyBhbmQgbG9uZ3MgYmVjYXVzZSBzb21lIHNhbXBsZXMgaGF2ZSBub24tdW5pcXVlIGxhdHMgYW5kIGxvbmdzISBTbyBJIGRvIGEgam9pbiBhbmQgdGFrZSB0aGUgZmlyc3QgbWF0Y2guCiAgbG9jczwtam9pbihsb2NzLHNwW2MoInNhbXBsZSIsImRlY2ltYWxMb25naXR1ZGUiLCJkZWNpbWFsTGF0aXR1ZGUiLAogICAgICAgICAgICAgICAgICAgICAgICJCb3dlbiIsIkt1bGJpY2tpX3IiLCJSRUFMTSIpXSwgYnk9InNhbXBsZSIsIG1hdGNoPSJmaXJzdCIpCiAgCiAgCiAgI3NvcnQgZ3NsRlNUbQogIGdzbEZTVG08LWdzbEZTVG1bb3JkZXIocm93bmFtZXMoZ3NsRlNUbSkpLG9yZGVyKGNvbG5hbWVzKGdzbEZTVG0pKV0KICAjIGNvbnZlcnQgdG8gZGF0YSBmcmFtZSB3aXRoIHBvcHNhbXBsZSBuYW1lcyBhcyBmaXJzdCBjb2x1bW4KICBnc2xGU1RtPC1jYmluZChzYW1wbGU9bG9jcyRzYW1wbGUsYXMuZGF0YS5mcmFtZShnc2xGU1RtKSkKICAKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyAzLiBDYWxjdWxhdGUgR3JlYXQgQ2lyY2xlIERpc3RhbmNlCiAgZ2NkaXN0X2ttIDwtIHBvaW50RGlzdGFuY2UobG9jc1ssMjozXSxsb25sYXQ9VCkvMTAwMAogICNzeW1tZXRyaWNpemUgdGhlIG1hdHJpeAogIGdjZGlzdF9rbVt1cHBlci50cmkoZ2NkaXN0X2ttKV08LXQoZ2NkaXN0X2ttKVt1cHBlci50cmkoZ2NkaXN0X2ttKV0KICAKICAjY2JpbmQgb24gdGhlIHNhbXBsZSBuYW1lcwogIGdjZGlzdF9rbSA8LSBjYmluZChzYW1wbGU9bG9jcyRzYW1wbGUsYXMuZGF0YS5mcmFtZShnY2Rpc3Rfa20pKQogIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIzQuIEZ1bGwgTW9kZWwKICAKICBjYXQoIlJ1bm5pbmcgRnVsbCBNb2RlbCIpCiAgCiAgCiAgcmVnaW9uczwtY2JpbmQobG9jc1ssYygxLDIsMyldLFJFQUxNPXJlcF9sZW4oMSxsZW5ndGgobG9jc1ssMV0pKSkKICBpZihsZW5ndGgodW5pcXVlKGxvY3MkUkVBTE0pKSA+IDEpewogICAgcmVnaW9uczwtY2JpbmQobG9jc1ssYygxLDIsMyldLHdpdGgobG9jcywgZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgoflJFQUxNKzApKSkpCiAgfQogIAogIGdzbEZTVG1sbDwtY2JpbmQobG9jc1ssYygyLDMpXSxnc2xGU1RtKQogIAogIGdkbS5mb3JtYXQuZnVsbDwtZm9ybWF0c2l0ZXBhaXIoYmlvRGF0YT1nc2xGU1RtLCBiaW9Gb3JtYXQ9MywgcHJlZERhdGE9cmVnaW9ucyxYQ29sdW1uID0gImRlY2ltYWxMb25naXR1ZGUiLCBZQ29sdW1uID0gImRlY2ltYWxMYXRpdHVkZSIsIHNpdGVDb2x1bW49InNhbXBsZSIsIGRpc3RQcmVkcz1saXN0KGdjZGlzdF9rbSkpCiAgCiAgICAgI3phcCBwb3B1bGF0aW9uIHBhaXJzIHdpdGggMCBnZW9ncmFwaGljYWwgZGlzdGFuY2UgYmV0d2VlbiB0aGVtLiBUcm91YmxpbmcuCiAgICB6YXBzPC13aGljaChnZG0uZm9ybWF0LmZ1bGwkczIubWF0cml4XzE9PTApCiAgICAKICAgIGlmKGxlbmd0aCh6YXBzKT4wKSB7CiAgICBnZG0uZm9ybWF0LmZ1bGw8LWdkbS5mb3JtYXQuZnVsbFstemFwcyxdCiAgICB9CiAgCiAgIyBydW4gdGhlIGZ1bGwgbW9kZWwsIGFuZCB0aGUgbW9kZWwgd2l0aCBvbmx5IGRpc3RhbmNlCiAgZnVsbGdkbTwtZ2RtKGdkbS5mb3JtYXQuZnVsbCkKICBkaXN0Z2RtPC1nZG0oZ2RtLmZvcm1hdC5mdWxsWyxjKDE6NixncmVwKCJtYXRyaXhfMSIsbmFtZXMoZ2RtLmZvcm1hdC5mdWxsKSkpXSkKICAKICAKICAjaWYgbm8gc29sdXRpb24sIHRoZW4ga2VlcCB0aGUgbmFtZXMgb2YgdGhlIHJlZ2lvbnMgZm9yIHRoaXMgc3BlY2llcyBpbiBhIG1hdHJpeCB3aXRoIHplcm8gdmFsdWVzCiAgaWYoaXMubnVsbChmdWxsZ2RtKSB8IGlzLm51bGwoZGlzdGdkbSkpewogICAgICAgIGNhdCgiTm8gc29sdXRpb24gb2J0YWluZWQgb24gRnVsbCBNb2RlbCIpCiAgICAgICAgcmVnaW9uczI8LXJlZ2lvbnNbMSwtYygxOjMpXQogICAgICAgIAogICAgICAgICNzb21lIGZ1dHppbmcgdG8gZGVhbCB3aXRoIGRhdGFzZXRzIHdpdGggbm8gcHJlZGljdG9ycyBidXQgZGlzdGFuY2UgbWF0cml4CiAgICAgICAgaWYobGVuZ3RoKHJlZ2lvbnMyKT4xKXtyZWdpb25zMlsxLF08LTB9CiAgICAgICAgcmVnaW9uczIkbWF0cml4XzE8LTAKICAgICAgICByZWdpb25zMiRTcGVjaWVzPC1nc2wKICAgICAgICBpZighaXMuZGF0YS5mcmFtZShyZWdpb25zMikpe3JlZ2lvbnMyPC1kYXRhLmZyYW1lKG1hdHJpeF8xPTApfQogICAgICAgIAogICAgICAgIG5vc29sdXRpb24uZnVsbFtbZ3NsXV08LXJlZ2lvbnMyCiAgICAgICAgbm9zb2x1dGlvbi5saXN0W1tnc2xdXTwtZ2RtLmZvcm1hdC5mdWxsCiAgICAgICAgcGxvdChnZG0uZm9ybWF0LmZ1bGwkczIubWF0cml4XzEsZ2RtLmZvcm1hdC5mdWxsJGRpc3RhbmNlLCBtYWluPWdzbCkKICAgICAgICBuZXh0fQogIAogICMgcHVsbCBvdXQgc3RhdHMKICAgI2RpZmZlcmVuY2UgaW4gZGV2aWFuY2UKICAgIGRlbHRhZGV2LnJlZ2lvbnM8LWRpc3RnZG0kZ2RtZGV2aWFuY2UtZnVsbGdkbSRnZG1kZXZpYW5jZQogICAgCiAgICAjcGVyY2VudCBvZiBudWxsIGRldmlhbmNlIGV4cGxhaW5lZCBieSB0aGUgbW9kZWwgd2l0aCBqdXN0IGRpc3RhbmNlCiAgICBleHBsYWluZWRkZXYuZGlzdDwtZGlzdGdkbSRleHBsYWluZWQKICAgIAogICAgZ2RtLnJlZ2lvbnMuZGV2aWFuY2U8LWZ1bGxnZG0kZ2RtZGV2aWFuY2UKICAgIGdkbS5yZWdpb25zLmV4cGxhaW5lZDwtZnVsbGdkbSRleHBsYWluZWQKCiAgICBnZG0ubm8ucmVnaW9ucy5kZXZpYW5jZTwtZGlzdGdkbSRnZG1kZXZpYW5jZQogICAgZ2RtLm5vLnJlZ2lvbnMuZXhwbGFpbmVkPC1kaXN0Z2RtJGV4cGxhaW5lZAogIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICAgIyA0QS4gUGVyZm9ybSBNb250ZS1DYXJsbyBwZXJtdXRhdGlvbnMgdG8gZGV2ZWxvcCBhIG51bGwgZGlzdHJpYnV0aW9uIAogICAgIyAgICBvZiBkZXZpYW5jZSB2YWx1ZXMgYW5kIGRldGVybWluZSBzaWduaWZpY2FuY2UgKHB2YWx1ZSkKICAgIGdkbS5mb3JtYXQucmFuZC5mdWxsPC1nZG0uZm9ybWF0LmZ1bGwKICAgIHJhbmQuZGVsdGFzLmZ1bGw8LXZlY3RvcigpIAogICAgcmFuZC5leHBsYWluZWQuZnVsbDwtdmVjdG9yKCkKICAKICAgIHdoaWxlKGxlbmd0aChyYW5kLmRlbHRhcy5mdWxsKSA8IDEwMDApIHsKICAgICAgZ2RtLmZvcm1hdC5yYW5kLmZ1bGwkZGlzdGFuY2U8LXNhbXBsZShnZG0uZm9ybWF0LnJhbmQuZnVsbCRkaXN0YW5jZSxzaXplPWxlbmd0aChnZG0uZm9ybWF0LnJhbmQuZnVsbCRkaXN0YW5jZSkpCiAgICAgIGdkbS5iYXJyaWVyLnJhbmQuZnVsbDwtZ2RtKGdkbS5mb3JtYXQucmFuZC5mdWxsKQogICAgICBnZG0ubm8uYmFycmllci5yYW5kLmZ1bGw8LWdkbShnZG0uZm9ybWF0LnJhbmQuZnVsbFssYygxOjYsZ3JlcCgibWF0cml4XzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMoZ2RtLmZvcm1hdC5yYW5kLmZ1bGwpKSldKQogICAgCiAgICAgICAgIyBpZiBubyBzb2x1dGlvbiBvYnRhaW5lZCwgZ28gdG8gbmV4dCBnc2wKICAgICAgaWYoaXMubnVsbChnZG0uYmFycmllci5yYW5kLmZ1bGwpIHwgaXMubnVsbChnZG0ubm8uYmFycmllci5yYW5kLmZ1bGwpKXtuZXh0fQogICAgICAKICAgICAgZGVsdGFkZXYucmFuZC5mdWxsPC1nZG0ubm8uYmFycmllci5yYW5kLmZ1bGwkZ2RtZGV2aWFuY2UtZ2RtLmJhcnJpZXIucmFuZC5mdWxsJGdkbWRldmlhbmNlCiAgICAgIGV4cGxhaW5lZC5yYW5kLmZ1bGw8LWdkbS5uby5iYXJyaWVyLnJhbmQuZnVsbCRleHBsYWluZWQKICAgICAgCiAgICAgIHJhbmQuZGVsdGFzLmZ1bGw8LWMocmFuZC5kZWx0YXMuZnVsbCxkZWx0YWRldi5yYW5kLmZ1bGwpCiAgICAgIHJhbmQuZXhwbGFpbmVkLmZ1bGw8LWMocmFuZC5leHBsYWluZWQuZnVsbCxleHBsYWluZWQucmFuZC5mdWxsKQogICAgfQogICAgcHZhbHVlX3JlZ2lvbnMuZnVsbDwtbGVuZ3RoKHdoaWNoKGFicyhkZWx0YWRldi5yZWdpb25zKSA8IGFicyhyYW5kLmRlbHRhcy5mdWxsKSkpL2xlbmd0aChyYW5kLmRlbHRhcy5mdWxsKQogICAgcHZhbHVlX2Rpc3QuZnVsbDwtbGVuZ3RoKHdoaWNoKGFicyhleHBsYWluZWRkZXYuZGlzdCkgPCBhYnMocmFuZC5leHBsYWluZWQuZnVsbCkpKS9sZW5ndGgocmFuZC5leHBsYWluZWQuZnVsbCkKICAgIAogICAgc3RhdHMuMTwtYyhnc2wsZ2RtLnJlZ2lvbnMuZGV2aWFuY2UsZ2RtLnJlZ2lvbnMuZXhwbGFpbmVkLGdkbS5uby5yZWdpb25zLmRldmlhbmNlLGdkbS5uby5yZWdpb25zLmV4cGxhaW5lZCxkZWx0YWRldi5yZWdpb25zLHB2YWx1ZV9yZWdpb25zLmZ1bGwscHZhbHVlX2Rpc3QuZnVsbCkKICAgIAogICAgc3RhdHMuZnVsbFtucm93KHN0YXRzLmZ1bGwpKzEsXTwtc3RhdHMuMQogICAgCiAgICBnZG0uZnVsbFtbZ3NsXV08LWZ1bGxnZG0KICAgIAogICAgCn0KICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBDYWxjdWxhdGUgT3ZlcndhdGVyIERpc3RhbmNlcyMKICAjU2F2ZSBmb3IgbGF0ZXIjIwogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyA1LiBDcmVhdGUgYSBzdWJzZXQgb2YgdGhlIGRpc3RhbmNlIG1hdHJpY2VzIGluY2x1ZGluZyBvbmx5IHRoZSBsb2NhbGl0aWVzIGZyb20KICAjICAgIHR3byBuZWlnaGJvcmluZyBWZXJvbiByZWdpb25zLgogIAogICNtYWtlIGEgdGFibGUgdG8ga2VlcCB0cmFjayBvZiBhbGwgdGhlc2UgdGVzdHMgZm9yIGVhY2ggc3BlY2llcwogIAojIGluZGl2aWR1YWwgYmFycmllciB0ZXN0cwogICMgZm9yKGogaW4gMToxNil7CiAgIyAgIGs8LWsrMQogICMgICBiYXJyaWVyPC1jKGJhcnJpZXJzW2osMV0sYmFycmllcnNbaiwyXSkKICAjICAgc3Vic2V0X2xvY3M8LXdoaWNoKGxvY3MkVmVyb25EaXZpcz09YmFycmllclsxXSB8IGxvY3MkVmVyb25EaXZpcz09YmFycmllclsyXSkKICAjICAgbG9jczI8LWxvY3Nbc3Vic2V0X2xvY3MsXQogICMgICAKICAjICAgCiAgIyAgIE51bXBvcHMxPC1sZW5ndGgobG9jczIkc2FtcGxlW3doaWNoKGxvY3MkVmVyb25EaXZpcz09YmFycmllclsxXSldKQogICMgICBOdW1wb3BzMjwtbGVuZ3RoKGxvY3MyJHNhbXBsZVt3aGljaChsb2NzJFZlcm9uRGl2aXM9PWJhcnJpZXJbMl0pXSkKICAjICAgCiAgIyAgIGNhdCgiTm93IFN0YXJ0aW5nIixiYXJyaWVyLCJcbiIpCiAgIyAgIAogICMgICBnY2Rpc3Rfa20yPC1nY2Rpc3Rfa21bc3Vic2V0X2xvY3MsYygxLHN1YnNldF9sb2NzKzEpXQogICMgICBnc2xGU1RtMjwtZ3NsRlNUbVtzdWJzZXRfbG9jcyxjKDEsc3Vic2V0X2xvY3MrMSldCiAgIyAgIAogICMgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICMgICAjIDYuIENyZWF0ZSBhIGR1bW15IGRpc3RhbmNlIG1hdHJpeCBmb3IgZWFjaCBwdXRhdGl2ZSAiYmFycmllciIgCiAgIyAgICMgICAgIGJldHdlZW4gdGhlIHR3byByZWdpb25zICgxcyBhbmQgMHMpCiAgIyAgIAogICMgICBiYXJyaWVyX20yPC1hcy5tYXRyaXgoZGlzdChhcy5udW1lcmljKGxvY3MyJFZlcm9uRGl2aXMgJWluJSBiYXJyaWVyWzFdKSkpCiAgIyAgIAogICMgICBiYXJyaWVyX20yIDwtIGNiaW5kKHNhbXBsZT1sb2NzMiRzYW1wbGUsYXMuZGF0YS5mcmFtZShiYXJyaWVyX20yKSkKICAjICAgCiAgIyAgICNpZiB0aGVyZSBhcmVuJ3QgZW5vdWdoIHNhbXBsZXMgb24gZWl0aGVyIHNpZGUgb2YgdGhpcyBiYXJyaWVyLCB0aGVuIHJlY29yZCB0aGlzIGFzIG5vbiB0ZXN0YWJsZSBhbmQgZ28gdG8gbmV4dCBiYXJyaWVyCiAgIyAgIGlmKE51bXBvcHMxK051bXBvcHMyIDwgMyl7Y2F0KCJMZXNzIHRoYW4gdGhyZWUgc2FtcGxlZCBwb3B1bGF0aW9uczsgbm90IHRlc3RhYmxlXG4iKTsgYmFycmllcnRlc3RzW2ssXTwtYyhnc2wsYmFycmllclsxXSxOdW1wb3BzMSxiYXJyaWVyWzJdLE51bXBvcHMyLEYsRik7bmV4dH0KICAjICAgaWYoIE51bXBvcHMxIDwgMSkge2NhdCgibm90IGVub3VnaCBwb3B1bGF0aW9ucyB3aXRoaW4iLGJhcnJpZXJbMV0sIlxuIikgOyBiYXJyaWVydGVzdHNbayxdPC1jKGdzbCxiYXJyaWVyWzFdLE51bXBvcHMxLGJhcnJpZXJbMl0sTnVtcG9wczIsRixGKTtuZXh0fQogICMgICBpZiggTnVtcG9wczIgPCAxKSB7Y2F0KCJub3QgZW5vdWdoIHBvcHVsYXRpb25zIHdpdGhpbiIsYmFycmllclsyXSwiXG4iKSA7IGJhcnJpZXJ0ZXN0c1trLF08LWMoZ3NsLGJhcnJpZXJbMV0sTnVtcG9wczEsYmFycmllclsyXSxOdW1wb3BzMixGLEYpO25leHR9CiAgIyAgIAogICMgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyAgICMgNy4gUnVuIHRocm91Z2ggZ2RtIHdpdGggdGhlIGJhcnJpZXIgYW5kIHdpdGhvdXQuIFNhdmUgdGhlIGRldmlhbmNlIHZhbHVlcy4KICAjICAgCiAgIyAgIGxvY3MyJHNhbXBsZTwtYXMuY2hhcmFjdGVyKGxvY3MyJHNhbXBsZSkKICAjICAgZ3NsRlNUbTIkc2FtcGxlPC1hcy5jaGFyYWN0ZXIoZ3NsRlNUbTIkc2FtcGxlKQogICMgICBnY2Rpc3Rfa20yJHNhbXBsZTwtYXMuY2hhcmFjdGVyKGdjZGlzdF9rbTIkc2FtcGxlKQogICMgICAKICAjICAgZ2RtLmZvcm1hdDwtZm9ybWF0c2l0ZXBhaXIoYmlvRGF0YT1nc2xGU1RtMiwgYmlvRm9ybWF0PTMsIHByZWREYXRhPWxvY3MyWywxOjNdLFhDb2x1bW4gPSAiZGVjaW1hbExvbmdpdHVkZSIsIFlDb2x1bW4gPSAiZGVjaW1hbExhdGl0dWRlIiwgc2l0ZUNvbHVtbj0ic2FtcGxlIiwgZGlzdFByZWRzPWxpc3QoZ2NkaXN0X2ttMixiYXJyaWVyX20yKSkKICAjICAgCiAgIyAgICAjemFwIHBvcHVsYXRpb24gcGFpcnMgd2l0aCAwIGdlb2dyYXBoaWNhbCBkaXN0YW5jZSBiZXR3ZWVuIHRoZW0uIFRyb3VibGluZy4KICAjICAgemFwczwtd2hpY2goZ2RtLmZvcm1hdCRzMi5tYXRyaXhfMT09MCkKICAjICAgCiAgIyAgIGlmKGxlbmd0aCh6YXBzKT4wKSB7CiAgIyAgIGdkbS5mb3JtYXQ8LWdkbS5mb3JtYXRbLXphcHMsXQogICMgICB9CiAgIyAgIAogICMgICAjcnVuIGdkbSB3aXRoIGFuZCB3aXRob3V0IHRoZSBiYXJyaWVyCiAgIyAgIGdkbS5iYXJyaWVyPC1nZG0oZ2RtLmZvcm1hdCkKICAjICAgZ2RtLm5vLmJhcnJpZXI8LWdkbShnZG0uZm9ybWF0WywtZ3JlcCgibWF0cml4XzIiLG5hbWVzKGdkbS5mb3JtYXQpKV0pCiAgIyAgIAogICMgICAjIHJ1biBtcmRtCiAgIyAgIG1yZG08LU1STShmb3JtdWxhID0gZGlzdGFuY2UgfiBzMi5tYXRyaXhfMSArIHMyLm1hdHJpeF8yLCBkYXRhPWdkbS5mb3JtYXQsbnBlcm0gPSAxMDAwMCkKICAjICAgCiAgIyAgICNUUk9VQkxFU0hPT1RJTkc6IHNhdmUgZnN0IG1hdHJpY2VzIGZyb20gZ2RtIG1vZGVscyB0aGF0IG9idGFpbiBubyBzb2x1dGlvbgogICMgICBpZihpcy5udWxsKGdkbS5iYXJyaWVyKSB8IGlzLm51bGwoZ2RtLm5vLmJhcnJpZXIpKQogICMgICAgIHtjYXQoIk5vIFNvbHV0aW9uIE9idGFpbmVkIFxuIik7CiAgIyAgICAgbm9zb2x1dGlvbltbcGFzdGUoZ3NsLGJhcnJpZXJbMV0sTnVtcG9wczEsYmFycmllclsyXSxOdW1wb3BzMixzZXA9IiwiKV1dPC1saXN0KGxvY3MyLGdjZGlzdF9rbTIsZ3NsRlNUbTIsZ2RtLmZvcm1hdCk7CiAgIyAgICAgYmFycmllcnRlc3RzW2ssXTwtYyhnc2wsYmFycmllclsxXSxOdW1wb3BzMSxiYXJyaWVyWzJdLE51bXBvcHMyLFQsRik7CiAgIyAgICAgbmV4dH0KICAjICAgCiAgIyAgICNkaWZmZXJlbmNlIGluIGRldmlhbmNlCiAgIyAgIGRlbHRhZGV2PC1nZG0ubm8uYmFycmllciRnZG1kZXZpYW5jZS1nZG0uYmFycmllciRnZG1kZXZpYW5jZQogICMgICAKICAjICAgI3BlcmNlbnQgb2YgbnVsbCBkZXZpYW5jZSBleHBsYWluZWQgYnkgdGhlIG1vZGVsIHdpdGgganVzdCBkaXN0YW5jZQogICMgICBleHBsYWluZWRkZXY8LWdkbS5uby5iYXJyaWVyJGV4cGxhaW5lZAogICMgICAKICAjICAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyAgICMgOC4gUGVyZm9ybSBNb250ZS1DYXJsbyBwZXJtdXRhdGlvbnMgdG8gZGV2ZWxvcCBhIG51bGwgZGlzdHJpYnV0aW9uIAogICMgICAjICAgIG9mIGRldmlhbmNlIHZhbHVlcyBhbmQgZGV0ZXJtaW5lIHNpZ25pZmljYW5jZSAocHZhbHVlKQogICMgICBnZG0uZm9ybWF0LnJhbmQ8LWdkbS5mb3JtYXQKICAjICAgcmFuZC5kZWx0YXM8LXZlY3RvcigpIAogICMgICByYW5kLmV4cGxhaW5lZDwtdmVjdG9yKCkKICAjICAgCiAgIyAgIHdoaWxlKGxlbmd0aChyYW5kLmRlbHRhcykgPCAxMDAwKSB7CiAgIyAgICAgZ2RtLmZvcm1hdC5yYW5kJGRpc3RhbmNlPC1zYW1wbGUoZ2RtLmZvcm1hdC5yYW5kJGRpc3RhbmNlLHNpemU9bGVuZ3RoKGdkbS5mb3JtYXQucmFuZCRkaXN0YW5jZSkpCiAgIyAgICAgZ2RtLmJhcnJpZXIucmFuZDwtZ2RtKGdkbS5mb3JtYXQucmFuZCkKICAjICAgICBnZG0ubm8uYmFycmllci5yYW5kPC1nZG0oZ2RtLmZvcm1hdC5yYW5kWywtZ3JlcCgibWF0cml4XzIiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKGdkbS5mb3JtYXQpKV0pCiAgIyAgICAgaWYoaXMubnVsbChnZG0uYmFycmllci5yYW5kKSB8IGlzLm51bGwoZ2RtLm5vLmJhcnJpZXIucmFuZCkpe25leHR9CiAgIyAgICAgZGVsdGFkZXYucmFuZDwtZ2RtLm5vLmJhcnJpZXIucmFuZCRnZG1kZXZpYW5jZS1nZG0uYmFycmllci5yYW5kJGdkbWRldmlhbmNlCiAgIyAgICAgZXhwbGFpbmVkLnJhbmQ8LWdkbS5uby5iYXJyaWVyLnJhbmQkZXhwbGFpbmVkCiAgIyAgICAgCiAgIyAgICAgcmFuZC5kZWx0YXM8LWMocmFuZC5kZWx0YXMsZGVsdGFkZXYucmFuZCkKICAjICAgICByYW5kLmV4cGxhaW5lZDwtYyhyYW5kLmV4cGxhaW5lZCxleHBsYWluZWQucmFuZCkKICAjICAgfQogICAgIyBwdmFsdWVfYmFycmllcjwtbGVuZ3RoKHdoaWNoKGFicyhkZWx0YWRldikgPCBhYnMocmFuZC5kZWx0YXMpKSkvbGVuZ3RoKHJhbmQuZGVsdGFzKQogICAgIyBwdmFsdWVfZGlzdDwtbGVuZ3RoKHdoaWNoKGFicyhleHBsYWluZWRkZXYpIDwgYWJzKHJhbmQuZXhwbGFpbmVkKSkpL2xlbmd0aChyYW5kLmV4cGxhaW5lZCkKICAjICAgCiAgIyAgIGNhdCgiR29vZCBTb2x1dGlvbiBcbiIpCiAgIyAgIAogICMgICAKICAjICAgI3NhdmUgc3RhdHMKICAjICAgZ2RtLmJhcnJpZXIuZGV2aWFuY2U8LWdkbS5iYXJyaWVyJGdkbWRldmlhbmNlCiAgIyAgIGdkbS5iYXJyaWVyLmV4cGxhaW5lZDwtZ2RtLmJhcnJpZXIkZXhwbGFpbmVkCiAgIyAKICAjICAgZ2RtLm5vLmJhcnJpZXIuZGV2aWFuY2U8LWdkbS5uby5iYXJyaWVyJGdkbWRldmlhbmNlCiAgIyAgIGdkbS5uby5iYXJyaWVyLmV4cGxhaW5lZDwtZ2RtLm5vLmJhcnJpZXIkZXhwbGFpbmVkCiAgIyAKICAjICAgaW1wdC5kaXN0LmdkbS5iYXJyaWVyPC1zdW0oZ2RtLmJhcnJpZXIkY29lZmZpY2llbnRzWzE6Z2RtLmJhcnJpZXIkc3BsaW5lc1sxXV0pCiAgIyAgIGltcHQuYmFycmllci5nZG0uYmFycmllcjwtc3VtKGdkbS5iYXJyaWVyJGNvZWZmaWNpZW50c1tnZG0uYmFycmllciRzcGxpbmVzWzFdKzE6Z2RtLmJhcnJpZXIkc3BsaW5lc1sxXV0pCiAgIyAgIGltcHQuZGlzdC5nZG0ubm8uYmFycmllcjwtc3VtKGdkbS5uby5iYXJyaWVyJGNvZWZmaWNpZW50c1sxOmdkbS5uby5iYXJyaWVyJHNwbGluZXNbMV1dKQogICMgICAKICAjICAgbXJkbS5yc3F1YXJlZDwtbXJkbSRyLnNxdWFyZWRbMV0KICAjICAgbXJkbS5yc3F1YXJlZC5wdmFsdWU8LW1yZG0kci5zcXVhcmVkWzJdCiAgIyAgIG1yZG0uZGlzdC5wdmFsdWU8LW1yZG0kY29lZlsyLDJdCiAgIyAgIG1yZG0uYmFycmllci5wdmFsdWU8LW1yZG0kY29lZlszLDJdCiAgIyAgIAogICMgICAKICAjICAKICAjICAgc3RhdHNfbW9kZWw8LWMoZ3NsLHBhc3RlKGJhcnJpZXJbMV0sYmFycmllclsyXSxzZXA9Ii0iKSxnZG0uYmFycmllci5kZXZpYW5jZSxnZG0uYmFycmllci5leHBsYWluZWQsIGltcHQuZGlzdC5nZG0uYmFycmllciwgaW1wdC5iYXJyaWVyLmdkbS5iYXJyaWVyLCBnZG0ubm8uYmFycmllci5kZXZpYW5jZSwgZ2RtLm5vLmJhcnJpZXIuZXhwbGFpbmVkLGltcHQuZGlzdC5nZG0ubm8uYmFycmllciwgZGVsdGFkZXYscHZhbHVlX2JhcnJpZXIscHZhbHVlX2Rpc3QsbXJkbS5yc3F1YXJlZCxtcmRtLnJzcXVhcmVkLnB2YWx1ZSxtcmRtLmRpc3QucHZhbHVlLG1yZG0uYmFycmllci5wdmFsdWUpCiAgIyAgIAogICMgICBzdGF0c1tucm93KHN0YXRzKSsxLF08LXN0YXRzX21vZGVsCiAgIyAgIAogICMgICAjcmVjb3JkIHRoaXMgaW4gdGhlIHRhYmxlCiAgIyAgIGJhcnJpZXJ0ZXN0c1trLF08LWMoZ3NsLGJhcnJpZXJbMV0sTnVtcG9wczEsYmFycmllclsyXSxOdW1wb3BzMixULFQpCiAgIyAgIAogICMgfQogIAoKCgoKc3RhdHMuZnVsbCRHRE0ucmVnaW9ucy5xdmFsdWU8LXAuYWRqdXN0KGFzLm51bWVyaWMoc3RhdHMuZnVsbCRQdmFsdWVfcmVnaW9ucyksbWV0aG9kPSJmZHIiKQpzdGF0cy5mdWxsJEdETS5kaXN0YW5jZS5xdmFsdWU8LXAuYWRqdXN0KGFzLm51bWVyaWMoc3RhdHMuZnVsbCRQdmFsdWVfZGlzdCksbWV0aG9kPSJmZHIiKQoKIyBzdGF0cyRHRE0ucXZhbHVlPC1wLmFkanVzdChhcy5udW1lcmljKHN0YXRzJFB2YWx1ZV9iYXJyaWVyKSxtZXRob2Q9ImZkciIpCiMgc3RhdHMkTVJETS5yMi5xdmFsdWU8LXAuYWRqdXN0KGFzLm51bWVyaWMoc3RhdHMkTVJETS5yc3F1YXJlZC5wdmFsdWUpLG1ldGhvZD0iZmRyIikKIyBzdGF0cyRNUkRNLmRpc3QucXZhbHVlPC1wLmFkanVzdChhcy5udW1lcmljKHN0YXRzJE1SRE0uZGlzdC5wdmFsdWUpLG1ldGhvZD0iZmRyIikKIyBzdGF0cyRNUkRNLmJhcnJpZXIucXZhbHVlPC1wLmFkanVzdChhcy5udW1lcmljKHN0YXRzJE1SRE0uYmFycmllci5wdmFsdWUpLG1ldGhvZD0iZmRyIikKCgoKIyAjIGRvIHNvbWUgZmlndXJpbmcgd2l0aCB0aGUgcmVzdWx0cwojIGxlbmd0aChiYXJyaWVydGVzdHNbd2hpY2goYmFycmllcnRlc3RzJFRlc3Q9PVQpLDFdKQojICN3b3JraW5nIEdETSB0ZXN0cwojIGxlbmd0aChiYXJyaWVydGVzdHNbd2hpY2goYmFycmllcnRlc3RzJFNvbHV0aW9uPT1UICYgYmFycmllcnRlc3RzJFRlc3Q9PVQpLDFdKQojICNmYWlsZWQgR0RNIHRlc3RzCiMgbGVuZ3RoKGJhcnJpZXJ0ZXN0c1t3aGljaChiYXJyaWVydGVzdHMkU29sdXRpb249PUYgJiBiYXJyaWVydGVzdHMkVGVzdD09VCksMV0pCiMgCiMgCiMgCiMgbGVuZ3RoKHN0YXRzW3doaWNoKHN0YXRzJEdETS5xdmFsdWUgPD0gMC4wMiksMV0pCiMgCiMgbGVuZ3RoKHN0YXRzW3doaWNoKHN0YXRzJE1SRE0uYmFycmllci5xdmFsdWUgPD0gMC4wMiksMV0pCiMgCiMgI292ZXJsYXAgYmV0d2VlbiBNUkRNIGFuZCBHRE0KIyBsZW5ndGgoc3RhdHNbd2hpY2goc3RhdHMkR0RNLnF2YWx1ZSA8PSAwLjAyICYgc3RhdHMkTVJETS5iYXJyaWVyLnF2YWx1ZSA8PSAwLjAyKSwxXSkKIyAKIyAKIyAKIyAKIyAKIyBnb29kYmFycmllcnM8LXN0YXRzICU+JSBmaWx0ZXIoR0RNLnF2YWx1ZSA8IDAuMDIpICU+JSBncm91cF9ieShCYXJyaWVyKSAlPiUgc3VtbWFyaXplKGdvb2RiYXJyaWVycyA9IG4oKSkKIyAKIyBhbGxiYXJyaWVyczwtc3RhdHMgJT4lIGdyb3VwX2J5KEJhcnJpZXIpICU+JSBzdW1tYXJpemUoYmFycmllcl90ZXN0cyA9IG4oKSkKIyAKIyBiYXJyaWVyX3JhdGlvczwtbGVmdF9qb2luKGFsbGJhcnJpZXJzLGdvb2RiYXJyaWVycyxieT0iQmFycmllciIpCiMgCiMgYmFycmllcl9yYXRpb3MkZ29vZGJhcnJpZXJzW3doaWNoKGlzLm5hKGJhcnJpZXJfcmF0aW9zJGdvb2RiYXJyaWVycykpXTwtMAojIAojIGJhcnJpZXJfcmF0aW9zPC1tdXRhdGUoYmFycmllcl9yYXRpb3MsIGdvb2RiYXJyaWVycy9iYXJyaWVyX3Rlc3RzKQojIAojIAojIGthYmxlKGJhcnJpZXJfcmF0aW9zKQojIAojIHdyaXRlLmNzdihzdGF0cywiLi9vdXRwdXQvR0RNX291dHB1dF9XQ1RoZXRhXzEwMDByZXBzLmNzdiIpCiMgd3JpdGUuY3N2KGJhcnJpZXJfcmF0aW9zLCAiLi9vdXRwdXQvR0RNX0pvc3REX1dDVGhldGFfYmFycmllcnMuY3N2IikKYGBgCgojIENyZWF0ZSBhIGhlYXRtYXAgZnJvbSBHRE0gcmVnaW9ucwpgYGB7ciBHRE0gSGVhdG1hcH0KCiNleHRyYWN0IHRoZSBpc3BsaW5lcwppc3BsaW5lczwtbGFwcGx5KGdkbS5mdWxsLGlzcGxpbmVFeHRyYWN0KQoKI2NyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgdGhlIGxhc3Qgcm93IG9mIGVhY2ggaXNwbGluZSA9IGltcG9ydGFuY2UsIGFuZCBsYXBwbHkgaXQKZ2RtLmltcG9ydGFuY2U8LWZ1bmN0aW9uKHApewogIHAkeVsyMDAsXQp9CmltcG9ydGFuY2U8LWxhcHBseShpc3BsaW5lcyxnZG0uaW1wb3J0YW5jZSkKCiMgY3JlYXRlIGEgZnVuY3Rpb24gdGhhdCB0cmFuc3Bvc2VzIGFuZCBjb252ZXJ0cyB0byBhIGRhdGEgZnJhbWUsIGFuZCBsYXBwbHkgaXQKZGF0YWZyYW1lcjwtZnVuY3Rpb24ocCl7CiAgcTwtYXMuZGF0YS5mcmFtZSh0KHApKQp9CgppbXBvcnRhbmNlMjwtbGFwcGx5KGltcG9ydGFuY2UsZGF0YWZyYW1lcikKCiNtZXJnZSB0aGUgbGlzdCBvZiBkYXRhZnJhbWVzIGFzIGZvdW5kIGhlcmU6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzgwOTEzMDMvc2ltdWx0YW5lb3VzbHktbWVyZ2UtbXVsdGlwbGUtZGF0YS1mcmFtZXMtaW4tYS1saXN0CmltcG9ydGFuY2VfZGY8LVJlZHVjZShmdW5jdGlvbih0MSx0MikgbWVyZ2UodDEsdDIsYWxsPVQsc29ydD1GKSwgaW1wb3J0YW5jZTIpCgojc2FtZSBmb3IgdGhlIG5vIHNvbHV0aW9uIHNldApub3NvbHV0aW9uX2RmPC1SZWR1Y2UoZnVuY3Rpb24odDEsdDIpIG1lcmdlKHQxLHQyLGFsbD1ULHNvcnQ9RiksIG5vc29sdXRpb24uZnVsbCkKCiNpbXBvcnRhbmNlX2RmPC1pbXBvcnRhbmNlX2RmW29yZGVyKHN0YXRzLmZ1bGwkR0RNLnJlZ2lvbnMucXZhbHVlKSxdCiNzdGF0cy5mdWxsPC1zdGF0cy5mdWxsW29yZGVyKHN0YXRzLmZ1bGwkR0RNLnJlZ2lvbnMucXZhbHVlKSxdCgojIGNvbnZlcnQgdG8gbWF0cml4CmltcG9ydGFuY2VfbWF0cml4PC1hcy5tYXRyaXgoaW1wb3J0YW5jZV9kZikKIyBzcGxpdCBpbnRvIHJlZ2lvbnMgY29tcG9uZW50CnJlZ2lvbnNfbWF0cml4PC1pbXBvcnRhbmNlX21hdHJpeFssMjpkaW0oaW1wb3J0YW5jZV9tYXRyaXgpWzJdXQojIGFuZCBkaXN0YW5jZSBjb21wb25lbnQKZGlzdGFuY2VfbWF0cml4PC1pbXBvcnRhbmNlX21hdHJpeFssMV0KCiMgc2V0IGltcG9ydGFuY2UgdmFsdWVzIGZvciBtb2RlbHMgdGhhdCB3aXRoIG5vbi1zaWduaWZpY2FudCByZWdpb25zIGNvbXBvbmVudCBhdCBxPDAuMDEgdG8gemVybwpyZWdpb25zX21hdHJpeFt3aGljaChzdGF0cy5mdWxsJEdETS5yZWdpb25zLnF2YWx1ZSA+IDAuMDEpLF1bIWlzLm5hKHJlZ2lvbnNfbWF0cml4W3doaWNoKHN0YXRzLmZ1bGwkR0RNLnJlZ2lvbnMucXZhbHVlID4gMC4wMSksXSldPC0wCgojIHNldCBpbXBvcnRhbmNlIHZhbHVlcyBmb3IgbW9kZWxzIHdpdGggbm9uLXNpZ25pZmljYW50IGRpc3RhbmNlIGNvbXBvbmVudCBhdCBxPDAuMDEgdG8gemVybwpkaXN0YW5jZV9tYXRyaXhbd2hpY2goc3RhdHMuZnVsbCRHRE0uZGlzdGFuY2UucXZhbHVlID4gMC4wMSldPC0wCgojIHN0aWNrIHRoZSBtYXRyaXggYmFjayB0b2dldGhlciBhbmQgdGhlbiBzY2FsZSBpbXBvcnRhbmNlIHRvIHJlbGF0aXZlIHZhbHVlcyBiYXNlZCBvbiBtYXggaW1wb3J0YW5jZQoKaW1wb3J0YW5jZV9tYXRyaXgyPC1jYmluZChkaXN0YW5jZV9tYXRyaXgscmVnaW9uc19tYXRyaXgpCgppbXBvcnRhbmNlX21hdHJpeDM8LWltcG9ydGFuY2VfbWF0cml4Mi9tYXgoaW1wb3J0YW5jZV9tYXRyaXgyLG5hLnJtID0gVCkKCmltcG9ydGFuY2VfZGYyPC1hcy5kYXRhLmZyYW1lKGltcG9ydGFuY2VfbWF0cml4Myxyb3cubmFtZXMgPSBzdGF0cy5mdWxsJFNwZWNpZXNfTG9jdXMpCgppbXBvcnRhbmNlX2RmMiRTcGVjaWVzPC1uYW1lcyhnZG0uZnVsbCkKCiNtZXJnZSBpbiB0aGUgbm9zb2x1dGlvbnMKbmFtZXMobm9zb2x1dGlvbl9kZilbMV08LSJkaXN0YW5jZV9tYXRyaXgiCmltcG9ydGFuY2VfZGYyPC1tZXJnZShpbXBvcnRhbmNlX2RmMiwgbm9zb2x1dGlvbl9kZixhbGw9VCkKCiNkZWxldGUgdGhlIHNwZWNpZXMgdGhhdCBvbmx5IG9jY3VycmVkIGluIG9uZSByZWdpb24sIHRoZW4gZGVsZXRlIHRoYXQgY29sdW1uCiNpbXBvcnRhbmNlX2RmMjwtaW1wb3J0YW5jZV9kZjJbd2hpY2goaXMubmEoaW1wb3J0YW5jZV9kZjIkVmVyb25EaXZpcykpLF0KaW1wb3J0YW5jZV9kZjI8LWltcG9ydGFuY2VfZGYyWywtd2hpY2gobmFtZXMoaW1wb3J0YW5jZV9kZjIpPT0iUkVBTE0iKV0KCgoKCgojIyBNYWtlIGEgaGVhdG1hcCBvZiB0aGUgaW1wb3J0YW5jZSB2YWx1ZXMKCiNtZWx0IGZvciBnZ3Bsb3QyCmltcG9ydGFuY2VfbWVsdGVkPC1tZWx0KGltcG9ydGFuY2VfZGYyLGlkLnZhcnMgPSAiU3BlY2llcyIpCmNvbG5hbWVzKGltcG9ydGFuY2VfbWVsdGVkKTwtYygiU3BlY2llcyIsIlZhcmlhYmxlIiwiSW1wb3J0YW5jZSIpCmltcG9ydGFuY2VfbWVsdGVkJFNwZWNpZXM8LWFzLmZhY3RvcihpbXBvcnRhbmNlX21lbHRlZCRTcGVjaWVzKQoKI2Jhc2VwbG90CmlwPC1nZ3Bsb3QoaW1wb3J0YW5jZV9tZWx0ZWQsYWVzKHk9U3BlY2llcyx4PVZhcmlhYmxlLGZpbGw9SW1wb3J0YW5jZSkpCgojYWRkIGdlb21fdGlsZSwgdHVybiB0aGUgeC1heGlzIGVsZW1lbnRzIGJ5IDkwIGRlZ3JlZXMsIHJldmVyc2UgdGhlIG5hbWVzIG9uIHRoZSB5LWF4aXMsIGFuZCB1c2UgYSBkaXZlcmdpbmcgY29sb3Igc2NoZW1lIHRvIGhpZ2hsaWdodCBoeXBvdGhlc2VzIHdpdGggPjUwJSByZWwgcHJvYi4KaXA8LWlwK2dlb21fdGlsZSgpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKwogIHlsaW0ocmV2KGxldmVscyhpbXBvcnRhbmNlX21lbHRlZCRTcGVjaWVzKSkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jKCJ3aGl0ZSIsInBpbmsiLCJyZWQiKSx2YWx1ZXMgPSBjKDAsMC4wMDAwMDEsMSksCiAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiZ3JleTUwIiwgZ3VpZGUgPSAiY29sb3VyYmFyIikKaXAKCgpgYGAKCiMgZGJSREEKCmBgYHtyIGRiUkRBfQoKIyByZWFkIGluIHRoZSBGc3QvUGhpU3QgdGFibGUgCmxvYWQoIn4vZ29vZ2xlX2RyaXZlL0RJUG5ldF9HYWl0X0xpZ19CaXJkL0RJUG5ldF9XRzRfZmlyc3RfcGFwZXJzL3N0YXRpc3RpY3MvQnlfU3BlY2llcy9QYWlyd2lzZV9zdGF0aXN0aWNzL3NhbXBsZS9ESVBuZXRfc3RydWN0dXJlX3NhbXBsZV9XQ1RoZXRhLlJkYXRhIikKI2xvYWQoIn4vRGVza3RvcC9ESVBuZXRfc3RydWN0dXJlX3NhbXBsZV9QaGlTVF8wNDI4MTcuUmRhdGEiKQoKCiMjMS4gRGF0YWZyYW1lIGZvciByZXN1bHRzCnN0YXRzPC1kYXRhLmZyYW1lKFNwZWNpZXNfTG9jdXM9Y2hhcmFjdGVyKDApLGNvbnN0cmFpbmVkLmluZXJ0aWE9bnVtZXJpYygwKSx0b3RhbEluZXJ0aWE9bnVtZXJpYygwKSxQcm9wb3J0aW9uQ29uc3RyYWluZWQ9bnVtZXJpYygwKSxhZGouUjIudG90YWw9bnVtZXJpYygwKSxtb2RlbEY9bnVtZXJpYygwKSxtb2RlbFB2YWx1ZT1udW1lcmljKDApLHBjeF9WYXI9bnVtZXJpYygwKSxwY3hfcD1udW1lcmljKDApLHBjeV9WYXI9bnVtZXJpYygwKSxwY3lfcD1udW1lcmljKDApLGJlc3Rtb2RlbD1jaGFyYWN0ZXIoMCksIGNvbnN0cmFpbmVkLmluZXJ0aWEuYmVzdD1udW1lcmljKDApLCB0b3RhbC5pbmVydGlhLmJlc3Q9bnVtZXJpYygwKSwgcHJvcG9ydGlvbi5jb25zdHJhaW5lZC5pbmVydGlhLmJlc3Q9bnVtZXJpYygwKSwgYWRqLlIyLmJlc3QubW9kZWw9bnVtZXJpYygwKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnN0YXRzJFNwZWNpZXNfTG9jdXM8LWFzLmNoYXJhY3RlcihzdGF0cyRTcGVjaWVzX0xvY3VzKQojc3RhdHMkQmFycmllcjwtYXMuY2hhcmFjdGVyKHN0YXRzJEJhcnJpZXIpCnN0YXRzJGJlc3Rtb2RlbDwtYXMuY2hhcmFjdGVyKHN0YXRzJGJlc3Rtb2RlbCkKCiMgTWFrZSBhbiBlbXB0eSBsaXN0IHRvIHNhdmUgcmRhIG91dHB1dCBmb3IgZWFjaCBzcGVjaWVzCmVzdV9sb2NpIDwtIHVuaXF1ZShpcGRiJEdlbnVzX3NwZWNpZXNfbG9jdXMpCmFsbC5nc2wucmRhPC1zYXBwbHkoZXN1X2xvY2ksIGZ1bmN0aW9uKHgpIE5VTEwpCgojbWFrZSBlbXB0eSBkYXRhIGZyYW1lcyB0byBzYXZlIHZhcmlhbmNlIGFuZCBwdmFsdWVzCnRlcm0udmFyczwtZGF0YS5mcmFtZShnc2w9Y2hhcmFjdGVyKDApKQp0ZXJtLnB2YWxzPC1kYXRhLmZyYW1lKGdzbD1jaGFyYWN0ZXIoMCkpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgMi4gU3Vic2FtcGxlIGZvciBlYWNoIHNwZWNpZXMgb2YgaW50ZXJlc3QsIGFuZCBmaWx0ZXIgYmFzZWQgb24gUGhpX1NUIHRhYmxlLgpmb3IoZ3NsIGluIGVzdV9sb2NpKXsgI2dzbDwtIkxpbmNraWFfbGFldmlnYXRhX0NPMSIgIlRyaWRhY25hX2Nyb2NlYV9DTzEiICJMdXRqYW51c19rYXNtaXJhX0NZQiIKICAKICBjYXQoIlxuIiwiXG4iLCJcbiIsIk5vdyBzdGFydGluZyIsIGdzbCwgIlxuIikKICAKICBpZihhbnkoaXMubmEoZGlmZnN0YXRzW1tnc2xdXSkpKXtjYXQoIk5BcyBpbiBGU1QgdGFibGUsIE5vIGRiUkRBIGNhbGN1bGF0ZWQiKTsgbmV4dH0KICAKICBpZihkaWZmc3RhdHNbW2dzbF1dPT0iRmV3ZXIgdGhhbiAzIHNhbXBsZWQgcG9wdWxhdGlvbnMgYWZ0ZXIgZmlsdGVyaW5nLiBObyBzdGF0cyBjYWxjdWxhdGVkIil7YWxsLmdzbC5yZGFbW2dzbF1dPC0iRmV3ZXIgdGhhbiA1IHNhbXBsZWQgcG9wdWxhdGlvbnMgYWZ0ZXIgZmlsdGVyaW5nLiI7IGNhdCgiRmV3ZXIgdGhhbiA1IHNhbXBsZWQgcG9wdWxhdGlvbnMgYWZ0ZXIgZmlsdGVyaW5nLiIpO25leHR9CiAgIHNwPC1pcGRiW3doaWNoKGlwZGIkR2VudXNfc3BlY2llc19sb2N1cz09Z3NsKSxdCiAgCiAgI2NsZWFuIHdlaXJkIGJhY2tzbGFzaGVzIGZyb20gbmFtZXMKICBzcCRsb2NhbGl0eTwtZ3N1YigiXCIiLCIiLHNwJGxvY2FsaXR5KQogIAogIHNwJHNhbXBsZTwtcGFzdGUoc3AkbG9jYWxpdHkscm91bmQoc3AkZGVjaW1hbExhdGl0dWRlLCBkaWdpdHM9MCkscm91bmQoc3AkZGVjaW1hbExvbmdpdHVkZSwgZGlnaXRzPTApLHNlcD0iXyIpICAjc2V0cyB1cCBhIHZhcmlhYmxlIHRoYXQgbWF0Y2hlcyB0aGUgbmFtZSBpbiBGc3QgdGFibGUKICBzcDwtc3Bbb3JkZXIoc3Akc2FtcGxlKSxdCiAgIyBOb3QgYWxsIGxvY2FsaXRpZXMgYXJlIGluY2x1ZGVkIGluIFZlcm9uJ3MgcmVnaW9uYWxpemF0aW9uIChlLmcuIEd1YW0pLCBzbyBnZXQgdGhlaXIgbmFtZXMgYW5kIHRoZW4gemFwIE5BcwogIG5vblZlcm9ucG9wczwtdW5pcXVlKHNwJHNhbXBsZVtpcy5uYShzcCRWZXJvbkRpdmlzKV0pCiAgc3A8LXNwWyFpcy5uYShzcCRWZXJvbkRpdmlzKSxdCiAgCiAgI3N1YnNhbXBsZSBGc3QgCiAgZ3NsRlNUPC1kaWZmc3RhdHNbW2dzbF1dCiAgI21ha2UgYSBtYXRyaXggb3V0IG9mIGdzbEZTVCwgY29udmVydCBuZWdhdGl2ZSB2YWx1ZXMgdG8gemVybwogIGdzbEZTVG08LWFzLm1hdHJpeChnc2xGU1QpCiAgZ3NsRlNUbVt3aGljaChnc2xGU1RtPDApXTwtMC4wCiAgCiAgI3phcCB3ZWlyZCBzbGFzaGVzIGluIHRoZSBuYW1lcwogIHJvd25hbWVzKGdzbEZTVG0pPC1nc3ViKCJcIiIsIiIscm93bmFtZXMoZ3NsRlNUbSkpCiAgY29sbmFtZXMoZ3NsRlNUbSk8LXJvd25hbWVzKGdzbEZTVG0pCiAgCiAgI3phcCB0aGUgc2FtZSBuYSBwb3B1bGF0aW9ucyBmcm9tIHRoZSBsaXN0IG9mIG5vbiBleGlzdGVudCBwb3BzIGZyb20gVmVyb25EaXZpcwogIGlmKGFueShyb3duYW1lcyhnc2xGU1RtKSAlaW4lIG5vblZlcm9ucG9wcykpewogICAgZ3NsRlNUbTwtZ3NsRlNUbVstKHdoaWNoKHJvd25hbWVzKGdzbEZTVG0pICVpbiUgbm9uVmVyb25wb3BzKSksLSh3aGljaChjb2xuYW1lcyhnc2xGU1RtKSAlaW4lIG5vblZlcm9ucG9wcykpXQogIH0KICBpZihsZW5ndGgocm93bmFtZXMoZ3NsRlNUbSkpPDUpe2FsbC5nc2wucmRhW1tnc2xdXTwtIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIjtjYXQoIkZld2VyIHRoYW4gNSBzYW1wbGVkIHBvcHVsYXRpb25zIik7bmV4dH0KICAKICAjYW5kIGZpbHRlciBzcCBiYXNlZCBvbiB0aGUgbG9jYWxpdGllcyB0aGF0IGhhdmUgRnN0IHZhbHVlcwogIHNwPC1zcFtzcCRzYW1wbGUgJWluJSByb3duYW1lcyhnc2xGU1RtKSxdCiAgCiAgI2FuZCB2aWNlIHZlcnNhCiAgCiAgZ3NsRlNUbTwtIGdzbEZTVG1bd2hpY2gocm93bmFtZXMoZ3NsRlNUbSkgJWluJSB1bmlxdWUoc3Akc2FtcGxlKSksd2hpY2gocm93bmFtZXMoZ3NsRlNUbSkgJWluJSB1bmlxdWUoc3Akc2FtcGxlKSldCiAgCgogIGlmKGxlbmd0aChyb3duYW1lcyhnc2xGU1RtKSk8NSl7YWxsLmdzbC5yZGFbW2dzbF1dPC0iRmV3ZXIgdGhhbiA1IHNhbXBsZWQgcG9wdWxhdGlvbnMiO2NhdCgiRmV3ZXIgdGhhbiA1IHNhbXBsZWQgcG9wdWxhdGlvbnMiKTtuZXh0fQogIAogICNjcmVhdGUgYSBsb2NhdGlvbnMgZGF0YSBmcmFtZSB0aGF0IGhhcyBhbGwgdGhlIGxvY2FsaXRpZXMgcGx1cyBsYXRzIGFuZCBsb25ncyBhbmQgdGhlaXIgVmVyb24gcmVnaW9uLgogIGxvY3M8LWFzLmRhdGEuZnJhbWUodW5pcXVlKHNwJHNhbXBsZSkpCiAgbmFtZXMobG9jcyk8LSJzYW1wbGUiCiAgI2xvY3MkTG9uZzwtc3AkZGVjaW1hbExvbmdpdHVkZVt3aGljaChsb2NzICVpbiUgc3Akc2FtcGxlKV0KICAjY2FuJ3QgZG8gYSB1bmlxdWUgb24gc2FtcGxlLCBsYXRzIGFuZCBsb25ncyBiZWNhdXNlIHNvbWUgc2FtcGxlcyBoYXZlIG5vbi11bmlxdWUgbGF0cyBhbmQgbG9uZ3MhIFNvIEkgZG8gYSBqb2luIGFuZCB0YWtlIHRoZSBmaXJzdCBtYXRjaC4KICBsb2NzPC1qb2luKGxvY3Msc3BbYygic2FtcGxlIiwiZGVjaW1hbExvbmdpdHVkZSIsImRlY2ltYWxMYXRpdHVkZSIKICAgICAgICAgICAgICAgICAgICAgICAsIlZlcm9uRGl2aXMiKV0sIGJ5PSJzYW1wbGUiLCBtYXRjaD0iZmlyc3QiKQogIGlmIChsZW5ndGgodW5pcXVlKGxvY3MkVmVyb25EaXZpcykpIDwgMikgeyJPbmx5IG9uZSByZWdpb24hIjsgY2F0KCJPbmx5IG9uZSByZWdpb24hIik7IG5leHR9CiAgCiAgI3NvcnQgZ3NsRlNUbQogIGdzbEZTVG08LWdzbEZTVG1bb3JkZXIocm93bmFtZXMoZ3NsRlNUbSkpLG9yZGVyKGNvbG5hbWVzKGdzbEZTVG0pKV0KCiAgCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICMgNC4gQ2FsY3VsYXRlIEdyZWF0IENpcmNsZSBEaXN0YW5jZQogIGdjZGlzdF9rbSA8LSBwb2ludERpc3RhbmNlKGxvY3NbLDI6M10sbG9ubGF0PVQpLzEwMDAKICAjIGFuZCBzeW1tZXRyaWNpc2UgaXQKICBnY2Rpc3Rfa21bdXBwZXIudHJpKGdjZGlzdF9rbSldPC0wCiAgZ2NkaXN0X2ttPC1nY2Rpc3Rfa20gKyB0KGdjZGlzdF9rbSkKICAgCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgQ2FsY3VsYXRlIE92ZXJ3YXRlciBEaXN0YW5jZXMjCiAgI1NhdmUgZm9yIGxhdGVyIyMKCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIzUuIENyZWF0ZSBhIG1hdHJpeCBvZiByZWdpb25hbCBpZGVudGl0aWVzCiAgCiAgcmVnaW9uczwtd2l0aChsb2NzLCBkYXRhLmZyYW1lKG1vZGVsLm1hdHJpeCh+VmVyb25EaXZpcyswKSkpICAgI29uZSBvZiB0aGUgcHJlZGljdG9ycyBpcyBzdXBlcmZsdW91cyBidXQgd2lsbCBnZXQga25vY2tlZCBvdXQgZHVyaW5nIFJEQQogIHJvdy5uYW1lcyhyZWdpb25zKTwtcm93Lm5hbWVzKGxvY3MpCiAgCgogICAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICAgIyA3LiBDYWxjdWxhdGUgdGhlIHByaW5jaXBhbCBjb29yZGluYXRlcwogICAgCiAgICBGU1QucGNvYTwtY21kc2NhbGUoZ3NsRlNUbSwgaz1kaW0oYXMubWF0cml4KGdzbEZTVG0pKVsxXSAtIDEsIGVpZz1UUlVFLCBhZGQ9RkFMU0UpICNpZ25vcmUgd2FybmluZ3MgLSBPSyB0byBoYXZlIG5lZ2F0aXZlcyBhY2NvcmRpbmcgdG8gQW5kZXJzb24KICAgIEZTVC5zY29yZXM8LUZTVC5wY29hJHBvaW50cwogICAgCiAgICBnY2Rpc3QucGNvYTwtY21kc2NhbGUoZ2NkaXN0X2ttLCBrPTIsIGVpZz1UUlVFLCBhZGQ9RkFMU0UpCiAgICBnY2Rpc3Quc2NvcmVzPC1nY2Rpc3QucGNvYSRwb2ludHMKICAgIGdjZGlzdC5zY29yZXM8LWRhdGEuZnJhbWUoInBjeCI9Z2NkaXN0LnBjb2EkcG9pbnRzWywxXSwicGN5Ij1nY2Rpc3QucGNvYSRwb2ludHNbLDJdKQogICAgbG9jczI8LWNiaW5kKHJlZ2lvbnMsZ2NkaXN0LnNjb3JlcykKICAgIAogICAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgICAjIDguIENhbGN1bGF0ZSB0aGUgUkRBIGFuZCBleHRyYWN0IHN0YXRpc3RpY3MKICAgIFJEQS5yZXM8LXJkYShGU1Quc2NvcmVzfi4sIGRhdGE9bG9jczIsIHNjYWxlPVRSVUUgKQogICAgCiAgICAjRXh0cmFjdCBTdGF0aXN0aWNzCiAgICBjb25zdHJhaW5lZC5pbmVydGlhPC1zdW1tYXJ5KFJEQS5yZXMpJGNvbnN0ci5jaGkKICAgIHRvdGFsLmluZXJ0aWE8LXN1bW1hcnkoUkRBLnJlcykkdG90LmNoaQogICAgcHJvcG9ydGlvbi5jb25zdHJhaW5lZC5pbmVydGlhPC1jb25zdHJhaW5lZC5pbmVydGlhL3RvdGFsLmluZXJ0aWEKICAgIAogICAgYWRqLlIyLnRvdGFsLm1vZGVsPC1Sc3F1YXJlQWRqKFJEQS5yZXMpJGFkai5yLnNxdWFyZWQKICAgIGlmKGlzLm5hKGFkai5SMi50b3RhbC5tb2RlbCkpe2NhdCgiUHJlZGljdG9ycyA+PSBPYnNlcnZhdGlvbnMhIE5vIHNvbHV0aW9uIik7YWxsLmdzbC5yZGFbW2dzbF1dPC0iUHJlZGljdG9ycyA+PSBPYnNlcnZhdGlvbnMhIE5vIHNvbHV0aW9uIjtuZXh0fQogICAgCiAgICBtb2RlbC5zaWc8LWFub3ZhLmNjYShSREEucmVzLCBzdGVwPTEwMDApCiAgICBtb2RlbEY8LW1vZGVsLnNpZyRGWzFdCiAgICBtb2RlbFB2YWx1ZTwtbW9kZWwuc2lnJGBQcig+RilgWzFdCiAgICAKICAgIHRlcm1zLnNpZzwtYW5vdmEoUkRBLnJlcywgYnk9InRlcm0iLCBzdGVwPTEwMDApCiAgICBwY3hfVmFyPC10ZXJtcy5zaWckVmFyaWFuY2VbMV0KICAgIHBjeF9wPC10ZXJtcy5zaWckYFByKD5GKWBbMV0KICAgIHBjeV9WYXI8LXRlcm1zLnNpZyRWYXJpYW5jZVsyXQogICAgcGN5X3A8LXRlcm1zLnNpZyRgUHIoPkYpYFsyXQogICAgCiAgICAjZXh0cmFjdCBhbGwgdmFyaWFuY2UgdmFsdWVzIGludG8gYSBkYXRhZnJhbWUKICAgIHRlcm0udmFyPC1hcy5kYXRhLmZyYW1lKHQodGVybXMuc2lnWywyXSkpCiAgICBuYW1lcyh0ZXJtLnZhcik8LXJvd25hbWVzKHRlcm1zLnNpZykKICAgCiAgICAjZXh0cmFjdCBhbGwgcC12YWx1ZXMgaW50byBhIGRhdGFmcmFtZQogICAgdGVybS5wdmFsPC1hcy5kYXRhLmZyYW1lKHQodGVybXMuc2lnWyw0XSkpCiAgICBuYW1lcyh0ZXJtLnB2YWwpPC1yb3duYW1lcyh0ZXJtcy5zaWcpCiAgICAKICAgICAKICAgICMgc2NhbGUgdGhlIHZhcmlhbmNlCiAgICB0ZXJtLnZhcjwtdGVybS52YXIvc3VtKHRlcm0udmFyKQogICAgCiAgICAjIHNldCB2YXJpYW5jZSB0byB6ZXJvIGlmIGl0IGlzIG5vdCBzaWduaWZpY2FudAogICAgdGVybS52YXJbMSx3aGljaCh0ZXJtLnB2YWxbMSxdID4gMC4wNSB8IGlzLm5hKHRlcm0ucHZhbFsxLF0pKV08LTAKICAgIAogICAgI3NldCBhbGwgdmFsdWVzIHRvIHplcm8gaWYgdGhlIG1vZGVsIGl0c2VsZiBpcyBub3Qgc2lnbmlmaWNhbnQKICAgIGlmKG1vZGVsUHZhbHVlID4gMC4wNSl7CiAgICB0ZXJtLnZhclsxLHdoaWNoKG5hbWVzKHRlcm0udmFyKSE9ImdzbCIpXTwtMAogICAgfQogICAgIyBhZGQgb24gdGhlIHNwZWNpZXMgbmFtZQogICAgdGVybS5wdmFsJGdzbDwtZ3NsCiAgICB0ZXJtLnZhciRnc2w8LWdzbAogICAgCiAgICAjbWVyZ2UgdGhlbSBvbiB0byBlYWNoIGRhdGFmcmFtZQogICAgdGVybS52YXJzPC1tZXJnZSh0ZXJtLnZhcnMsdGVybS52YXIsYWxsPVQpCiAgICB0ZXJtLnB2YWxzPC1tZXJnZSh0ZXJtLnB2YWxzLHRlcm0ucHZhbCxhbGw9VCkKICAgIAogICAgCiAgICAKICAgICNiYXJyaWVyX1ZhcjwtdGVybXMuc2lnJFZhcmlhbmNlWzNdICAgI29taXR0aW5nIGZvciBub3cgYXMgdGhlIG51bWJlciBvZiBiYXJyaWVycyB3aWxsIGRpZmZlcgogICAgI2JhcnJpZXJfcDwtdGVybXMuc2lnJGBQcig+RilgWzNdCiAgICAKICAgICNtYXJnLnNpZzwtYW5vdmEoUkRBLnJlcywgYnk9Im1hcmdpbiIsIHN0ZXA9MTAwMCkKICAgICNiYXJyaWVyX21hcmdWYXI8LW1hcmcuc2lnJFZhcmlhbmNlWzNdCiAgICAjYmFycmllcl9tYXJncDwtbWFyZy5zaWckYFByKD5GKWBbM10KICAgIAogICAgI01vZGVsIHNlbGVjdGlvbgogICAgbnVsbG1vZGVsPC1yZGEoRlNULnNjb3Jlc34xLCBkYXRhPWxvY3MyLCBzY2FsZT1UUlVFICkKICAgIGZvcndhcmQubW9kZWw8LW9yZGlSMnN0ZXAobnVsbG1vZGVsLCBzY29wZT1mb3JtdWxhKFJEQS5yZXMpLCBkaXJlY3Rvbj0iZm9yd2FyZCIsIHBzdGVwcz0xMDAwKSAgI29yZGlSMnN0ZXAgaW1wbGVtZW50cyBCbGFuY2hldHMgc3RvcHBpbmcgY3JpdGVyaW9uCiAgICBiZXN0bW9kZWw8LWFzLmNoYXJhY3Rlcihmb3J3YXJkLm1vZGVsJGNhbGxbMl0pCiAgICBpZiAoaXMubnVsbChzdW1tYXJ5KGZvcndhcmQubW9kZWwpJGNvbnN0ci5jaGkpKSB7CiAgICAgIGNvbnN0cmFpbmVkLmluZXJ0aWEuYmVzdDwtTkEKICAgICAgdG90YWwuaW5lcnRpYS5iZXN0PC1zdW1tYXJ5KGZvcndhcmQubW9kZWwpJHRvdC5jaGkKICAgICAgcHJvcG9ydGlvbi5jb25zdHJhaW5lZC5pbmVydGlhLmJlc3Q8LU5BCiAgICAgIGFkai5SMi5iZXN0Lm1vZGVsPC1OQQogICAgfSBlbHNlIHsKICAgICAgY29uc3RyYWluZWQuaW5lcnRpYS5iZXN0PC1zdW1tYXJ5KGZvcndhcmQubW9kZWwpJGNvbnN0ci5jaGkKICAgICAgdG90YWwuaW5lcnRpYS5iZXN0PC1zdW1tYXJ5KGZvcndhcmQubW9kZWwpJHRvdC5jaGkKICAgICAgcHJvcG9ydGlvbi5jb25zdHJhaW5lZC5pbmVydGlhLmJlc3Q8LWNvbnN0cmFpbmVkLmluZXJ0aWEuYmVzdC90b3RhbC5pbmVydGlhLmJlc3QKICAgICAgYWRqLlIyLmJlc3QubW9kZWw8LVJzcXVhcmVBZGooZm9yd2FyZC5tb2RlbCkkYWRqLnIuc3F1YXJlZAogICAgfQogICAgIAogIAogICAgI3NhdmUgc3RhdHMKICAgIAogICAgc3RhdHNfbW9kZWw8LWMoZ3NsLGNvbnN0cmFpbmVkLmluZXJ0aWEsdG90YWwuaW5lcnRpYSxwcm9wb3J0aW9uLmNvbnN0cmFpbmVkLmluZXJ0aWEsYWRqLlIyLnRvdGFsLm1vZGVsLG1vZGVsRixtb2RlbFB2YWx1ZSxwY3hfVmFyLHBjeF9wLHBjeV9WYXIscGN5X3AsIGJlc3Rtb2RlbCwgY29uc3RyYWluZWQuaW5lcnRpYS5iZXN0LCB0b3RhbC5pbmVydGlhLmJlc3QsIHByb3BvcnRpb24uY29uc3RyYWluZWQuaW5lcnRpYS5iZXN0LCBhZGouUjIuYmVzdC5tb2RlbCkKICAgIAogICAgc3RhdHNbbnJvdyhzdGF0cykrMSxdPC1zdGF0c19tb2RlbAogICAgYWxsLmdzbC5yZGFbW2dzbF1dPC1SREEucmVzCiAgICAKICAgIAogCiAgfQoKd3JpdGUuY3N2KHRlcm0udmFycyxmaWxlPSIuL291dHB1dC9kYlJEQV90ZXJtX3ZhcnNfV0NUSEVUQS5jc3YiKQp3cml0ZS5jc3YodGVybS5wdmFscyxmaWxlPSIuL291dHB1dC9kYlJEQV90ZXJtX3B2YWxzX1dDVEhFVEEuY3N2IikKCiBzYXZlKGFsbC5nc2wucmRhLGZpbGU9Ii4vb3V0cHV0L211bHRpYmFycmllcl9kYlJEQV9XQ1RIRVRBLlJkYXRhIikKICAKd3JpdGUuY3N2KHN0YXRzLCAiLi9vdXRwdXQvbXVsdGliYXJyaWVyX2RiUkRBX0pPU1RELmNzdiIpCiAgCmBgYAoKIyMgTWFrZSBhIGhlYXRtYXAgb2YgdGhlIHZhcmlhbmNlIHZhbHVlcwoKCmBgYHtyfQoKCiNtZWx0IGZvciBnZ3Bsb3QyCnZhcmlhbmNlX21lbHRlZDwtbWVsdCh0ZXJtLnZhcnMsaWQudmFycyA9ICJnc2wiKQpjb2xuYW1lcyh2YXJpYW5jZV9tZWx0ZWQpPC1jKCJTcGVjaWVzIiwiVmFyaWFibGUiLCJQcm9wb3J0aW9uX29mX1ZhcmlhbmNlIikKdmFyaWFuY2VfbWVsdGVkJFNwZWNpZXM8LWFzLmZhY3Rvcih2YXJpYW5jZV9tZWx0ZWQkU3BlY2llcykKCiNiYXNlcGxvdApkYnJkYTwtZ2dwbG90KHZhcmlhbmNlX21lbHRlZCxhZXMoeT1TcGVjaWVzLHg9VmFyaWFibGUsZmlsbD1Qcm9wb3J0aW9uX29mX1ZhcmlhbmNlKSkKCiNhZGQgZ2VvbV90aWxlLCB0dXJuIHRoZSB4LWF4aXMgZWxlbWVudHMgYnkgOTAgZGVncmVlcywgcmV2ZXJzZSB0aGUgbmFtZXMgb24gdGhlIHktYXhpcywgYW5kIHVzZSBhIGRpdmVyZ2luZyBjb2xvciBzY2hlbWUgdG8gaGlnaGxpZ2h0IGh5cG90aGVzZXMgd2l0aCA+NTAlIHJlbCBwcm9iLgpkYnJkYTwtZGJyZGErZ2VvbV90aWxlKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkrCiAgeWxpbShyZXYobGV2ZWxzKHZhcmlhbmNlX21lbHRlZCRTcGVjaWVzKSkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jKCJ3aGl0ZSIsInBpbmsiLCJyZWQiKSx2YWx1ZXMgPSBjKDAsMC4wMDAwMDEsMSksCiAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiZ3JleTUwIiwgZ3VpZGUgPSAiY29sb3VyYmFyIikKCmRicmRhCmBgYAo=